@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
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"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"}
package/lib/types/i18n.js CHANGED
@@ -4,9 +4,9 @@
4
4
  *
5
5
  * Resolution order mirrors the `/theme` mechanism (see themePrefs.ts):
6
6
  *
7
- * 1. `CC_TUI_LANG` env var (`en` / `zh`) — pinned at process start
7
+ * 1. `DSH_TUI_LANG` env var (`en` / `zh`) — pinned at process start
8
8
  * 2. `lang` cordis.yml config key (see Config in index.ts)
9
- * 3. the persisted `/lang` choice in `~/.dsh-cc/lang.json`
9
+ * 3. the persisted `/lang` choice in `~/.dsh-tui/lang.json`
10
10
  * 4. the OS locale guess (`LC_ALL` / `LC_MESSAGES` / `LANG`)
11
11
  * 5. `zh` (the original hard-coded language)
12
12
  *
@@ -16,17 +16,17 @@
16
16
  * key itself so a typo is visible in the UI instead of silently blank.
17
17
  */
18
18
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
19
- import { homedir } from 'node:os';
20
19
  import { join } from 'node:path';
21
- const PREFS_DIR = join(homedir(), '.dsh-cc');
20
+ import { DATA_DIR } from './utils/paths.js';
21
+ const PREFS_DIR = DATA_DIR;
22
22
  /** The languages shipped with the plugin, in display order. */
23
23
  export const LANGS = ['zh', 'en'];
24
24
  const dict = {
25
25
  // ── channel.ts ───────────────────────────────────────────────────────
26
26
  'activity-indicator-already': { zh: '指示器已是:{{name}}', en: 'Indicator already set: {{name}}' },
27
27
  'activity-indicator-switched': { zh: '指示器已切换:{{name}}(已保存)', en: 'Indicator switched: {{name}} (saved)' },
28
- 'activity-pref-write-failed': { zh: '无法写入 ~/.dsh-cc/working-activity.json,切换未保存', en: 'Cannot write ~/.dsh-cc/working-activity.json, switch not saved' },
29
- 'model-pref-write-failed': { zh: '无法写入 ~/.dsh-cc/model.json,模型选择不会保存到重启后', en: 'Cannot write ~/.dsh-cc/model.json, the model choice will not survive a restart' },
28
+ 'activity-pref-write-failed': { zh: '无法写入 ~/.dsh-tui/working-activity.json,切换未保存', en: 'Cannot write ~/.dsh-tui/working-activity.json, switch not saved' },
29
+ 'model-pref-write-failed': { zh: '无法写入 ~/.dsh-tui/model.json,模型选择不会保存到重启后', en: 'Cannot write ~/.dsh-tui/model.json, the model choice will not survive a restart' },
30
30
  'model-route-invalid': { zh: '持久化的模型路由 {{provider}}/{{model}} 不在该 provider 的模型列表中,已整体回退到 {{fallback}}', en: 'Persisted model route {{provider}}/{{model}} is not advertised by that provider; fell back to {{fallback}}' },
31
31
  'unknown-activity-preset': { zh: '未知预设「{{name}}」· /activity frames 查看全部', en: 'Unknown preset "{{name}}" · /activity frames to view all' },
32
32
  'preset-unavailable': { zh: 'Preset 不可用——当前组合未挂载 agent-presets 名册', en: 'Preset unavailable — the agent-presets roster is not mounted' },
@@ -34,7 +34,7 @@ const dict = {
34
34
  'preset-not-found': { zh: 'Preset「{{id}}」不存在 · {{err}}', en: 'Preset "{{id}}" not found · {{err}}' },
35
35
  'preset-load-failed': { zh: 'Preset「{{id}}」无法加载 · {{broken}}', en: 'Preset "{{id}}" failed to load · {{broken}}' },
36
36
  'preset-already-current': { zh: '当前 preset 已是:{{id}}', en: 'Current preset already: {{id}}' },
37
- 'preset-pref-write-failed': { zh: '无法写入 ~/.dsh-cc/agent-preset.json,选择未保存', en: 'Cannot write ~/.dsh-cc/agent-preset.json, selection not saved' },
37
+ 'preset-pref-write-failed': { zh: '无法写入 ~/.dsh-tui/agent-preset.json,选择未保存', en: 'Cannot write ~/.dsh-tui/agent-preset.json, selection not saved' },
38
38
  'preset-locked-saved-default': { zh: '会话已开始,preset 已锁定(当前:{{current}})· 已保存为默认:{{id}}(/new 或下次启动生效)', en: 'Session already started, preset locked (current: {{current}}) · Saved as default: {{id}} (applies on /new or next start)' },
39
39
  'preset-switch-failed': { zh: 'Preset 切换失败 · {{err}}', en: 'Preset switch failed · {{err}}' },
40
40
  'preset-switched-pref-failed': { zh: 'Preset 已切换:{{id}},但默认偏好写入失败(重启后不保留)', en: 'Preset switched: {{id}}, but writing the default preference failed (won\'t persist after restart)' },
@@ -75,6 +75,7 @@ const dict = {
75
75
  'doctor-config-missing': { zh: '(不存在)', en: '(missing)' },
76
76
  'doctor-storage': { zh: '会话存储: {{dir}} {{state}}', en: 'Session storage: {{dir}} {{state}}' },
77
77
  'doctor-storage-uninit': { zh: '(未初始化)', en: '(not initialized)' },
78
+ 'doctor-legacy-dir': { zh: '旧数据目录: ~/.dsh-tui 仍存在(已迁移到 ~/.dsh-tui,确认无误后可自行删除)', en: 'Legacy data directory: ~/.dsh-tui still exists (migrated to ~/.dsh-tui; delete it yourself once satisfied)' },
78
79
  'subagent-not-mounted': { zh: '子代理服务未挂载(leaf 未启用 subagent)', en: 'Subagent service not mounted (leaf has no subagent)' },
79
80
  'subagent-none': { zh: '当前会话暂无子代理', en: 'No subagents in the current session' },
80
81
  'subagent-resumable': { zh: '可续', en: 'resumable' },
@@ -84,6 +85,32 @@ const dict = {
84
85
  'subagent-archived': { zh: ' 已归档', en: ' archived' },
85
86
  'subagent-query-failed': { zh: '查询失败 · {{err}}', en: 'Query failed · {{err}}' },
86
87
  'agent-preset-switched': { zh: 'Agent preset 已切换:{{preset}}', en: 'Agent preset switched: {{preset}}' },
88
+ 'context-low-warning': { zh: '上下文即将耗尽(剩余 {{percent}}%)· 运行 /clear 或新建会话', en: 'Context low ({{percent}}% remaining) · Run /clear or start a new session' },
89
+ 'rewind-unavailable': { zh: '回退不可用——会话服务未加载', en: 'Rewind unavailable — session services not loaded' },
90
+ 'rewind-settling': { zh: '无法回退——回合仍在收尾,请稍候再试', en: 'Cannot rewind — the turn is still settling, try again in a moment' },
91
+ 'rewind-fork-failed': { zh: '无法回退到该处 · {{err}}', en: 'Cannot rewind to this point · {{err}}' },
92
+ 'rewind-create-failed': { zh: '回退失败——无法创建替代会话', en: 'Rewind failed — could not create the replacement session' },
93
+ 'rewind-attach-failed': { zh: '已回退,但工作区挂载失败 · {{err}}', en: 'Session rewound, but workspace attachment failed · {{err}}' },
94
+ 'resume-while-working': { zh: '回合运行中,无法恢复会话', en: 'Cannot resume while a turn is running' },
95
+ 'resume-unavailable': { zh: '恢复不可用——agents 服务未加载', en: 'Resume unavailable — agents service not loaded' },
96
+ 'resume-failed': { zh: '恢复失败 · {{err}}', en: 'Resume failed · {{err}}' },
97
+ 'resume-attach-failed': { zh: '已恢复会话,但工作区挂载失败 · {{err}}', en: 'Session resumed, but workspace attachment failed · {{err}}' },
98
+ 'new-session-while-working': { zh: '回合运行中,无法新建会话', en: 'Cannot start a new session while a turn is running' },
99
+ 'new-session-unavailable': { zh: '新建会话不可用——agents 服务未加载', en: 'New session unavailable — agents service not loaded' },
100
+ 'new-session-failed': { zh: '新建会话失败 · {{err}}', en: 'New session failed · {{err}}' },
101
+ 'new-session-attach-failed': { zh: '会话已创建,但工作区挂载失败 · {{err}}', en: 'Session created, but workspace attachment failed · {{err}}' },
102
+ 'model-switch-while-working': { zh: '回合运行中,无法切换模型', en: 'Cannot switch models while a turn is running' },
103
+ 'model-switch-unavailable': { zh: '模型切换不可用——会话服务未加载', en: 'Model switch unavailable — session services not loaded' },
104
+ 'model-switch-fork-failed': { zh: '无法切换模型 · {{err}}', en: 'Cannot switch models · {{err}}' },
105
+ 'model-switch-failed': { zh: '模型切换失败 · {{err}}', en: 'Model switch failed · {{err}}' },
106
+ 'model-switch-attach-failed': { zh: '模型已切换,但工作区挂载失败 · {{err}}', en: 'Model switched, but workspace attachment failed · {{err}}' },
107
+ 'compact-unavailable': { zh: '压缩不可用——当前 leaf 没有压缩服务', en: 'Compaction unavailable · no compaction service in this leaf' },
108
+ 'compact-while-working': { zh: '回合运行中,无法压缩会话', en: 'Cannot compact while a turn is running' },
109
+ 'compact-working': { zh: '正在压缩会话…', en: 'Compacting conversation…' },
110
+ 'compact-done': { zh: '会话已压缩', en: 'Conversation compacted' },
111
+ 'compact-nothing': { zh: '没有可压缩的内容', en: 'Nothing to compact' },
112
+ 'compact-failed': { zh: '压缩失败 · {{err}}', en: 'Compaction failed · {{err}}' },
113
+ 'turn-failed': { zh: '回合出错{{detail}}', en: 'Turn error{{detail}}' },
87
114
  // ── questions.ts ─────────────────────────────────────────────────────
88
115
  'questionnaire-answered': { zh: '📋 问卷已答 · {{total}} 题', en: '📋 Questionnaire answered · {{total}} questions' },
89
116
  // ── customTheme.ts (doc example only) ───────────────────────────────
@@ -108,7 +135,7 @@ const dict = {
108
135
  'activity-usage-name': { zh: '/activity frames <名>', en: '/activity frames <name>' },
109
136
  'activity-current-preset': { zh: '当前预设 {{name}}', en: 'Current preset {{name}}' },
110
137
  'activity-switch-hint': { zh: '切换 /activity(选择器)或 /activity frames <名>', en: 'Switch /activity (picker) or /activity frames <name>' },
111
- 'activity-persist-hint': { zh: '持久化 ~/.dsh-cc/working-activity.json(重启后仍生效)', en: 'Persisted ~/.dsh-cc/working-activity.json (survives restart)' },
138
+ 'activity-persist-hint': { zh: '持久化 ~/.dsh-tui/working-activity.json(重启后仍生效)', en: 'Persisted ~/.dsh-tui/working-activity.json (survives restart)' },
112
139
  'activity-current-direct': { zh: '当前预设:{{name}} · /activity frames <名> 直接切换:', en: 'Current preset: {{name}} · /activity frames <name> to switch directly:' },
113
140
  'activity-random-each': { zh: '每次随机', en: 'random each time' },
114
141
  'activity-current-marker': { zh: ' ← 当前', en: ' ← current' },
@@ -116,14 +143,15 @@ const dict = {
116
143
  'preset-current': { zh: '当前 preset {{name}}', en: 'Current preset {{name}}' },
117
144
  'preset-roster-missing': { zh: '(未挂载名册)', en: '(roster not mounted)' },
118
145
  'preset-switch-hint': { zh: '切换 /preset(选择器)或 /preset <id>', en: 'Switch /preset (picker) or /preset <id>' },
119
- 'preset-persist-hint': { zh: '持久化 ~/.dsh-cc/agent-preset.json(重启后仍生效;cordis.yml preset 优先)', en: 'Persisted ~/.dsh-cc/agent-preset.json (survives restart; cordis.yml preset wins)' },
146
+ 'preset-persist-hint': { zh: '持久化 ~/.dsh-tui/agent-preset.json(重启后仍生效;cordis.yml preset 优先)', en: 'Persisted ~/.dsh-tui/agent-preset.json (survives restart; cordis.yml preset wins)' },
120
147
  'preset-lock-hint': { zh: '锁定规则 已开始的会话不可切换(官方 blank-only 规则)', en: 'Lock rule started sessions cannot switch (official blank-only rule)' },
121
148
  'preset-roster-unmounted': { zh: '当前组合未挂载 agent-presets 名册(preset 不可用)', en: 'The agent-presets roster is not mounted (presets unavailable)' },
122
149
  'theme-name-arg': { zh: '/theme <名字>', en: '/theme <name>' },
123
150
  'theme-current': { zh: '当前主题 {{name}}', en: 'Current theme {{name}}' },
124
151
  'theme-switch-hint': { zh: '切换 /theme(选择器)或 /theme <名字>', en: 'Switch /theme (picker) or /theme <name>' },
125
- 'theme-persist-hint': { zh: '持久化 ~/.dsh-cc/theme.json(重启后仍生效;CC_TUI_THEME 优先)', en: 'Persisted ~/.dsh-cc/theme.json (survives restart; CC_TUI_THEME wins)' },
126
- 'theme-custom-hint': { zh: '自定义 ~/.dsh-cc/themes/<名字>.json(见 README「自定义主题」)', en: 'Custom ~/.dsh-cc/themes/<name>.json (see README "Custom themes")' },
152
+ 'theme-persist-hint': { zh: '持久化 ~/.dsh-tui/theme.json(重启后仍生效;DSH_TUI_THEME 优先)', en: 'Persisted ~/.dsh-tui/theme.json (survives restart; DSH_TUI_THEME wins)' },
153
+ 'theme-custom-hint': { zh: '自定义 ~/.dsh-tui/themes/<名字>.json(见 README「自定义主题」)', en: 'Custom ~/.dsh-tui/themes/<name>.json (see README "Custom themes")' },
154
+ 'theme-auto-resolved': { zh: '自动解析 当前为 {{name}}(跟随终端背景)', en: 'Auto-resolved currently {{name}} (follows terminal background)' },
127
155
  'theme-switched-saved': { zh: '主题已切换:{{name}}(已保存)', en: 'Theme switched: {{name}} (saved)' },
128
156
  'theme-unknown': { zh: '未知主题「{{name}}」· /theme 查看全部', en: 'Unknown theme "{{name}}" · /theme to view all' },
129
157
  'status-model': { zh: '模型 {{model}}', en: 'Model {{model}}' },
@@ -132,6 +160,28 @@ const dict = {
132
160
  'status-state': { zh: '状态 {{state}}', en: 'Status {{state}}' },
133
161
  'status-session': { zh: '会话 {{id}}', en: 'Session {{id}}' },
134
162
  'status-dir': { zh: '目录 {{cwd}}', en: 'Directory {{cwd}}' },
163
+ 'workspace-picker-title': { zh: '工作区', en: 'Workspace' },
164
+ 'workspace-picker-hint': { zh: '**Enter** 切换并新建会话 · Esc 退出 · 也可输入 /workspace open <路径或 URI>', en: '**Enter** switch and start a new session · Esc to exit · or type /workspace open <path-or-URI>' },
165
+ 'workspace-none': { zh: '没有可用工作区', en: 'No workspaces available' },
166
+ 'workspace-list-failed': { zh: '读取工作区失败 · {{err}}', en: 'Failed to list workspaces · {{err}}' },
167
+ 'workspace-uri-invalid': { zh: '无法解析工作区目标:{{uri}}', en: 'Cannot resolve workspace target: {{uri}}' },
168
+ 'workspace-uri-failed': { zh: '加载工作区失败 · {{err}}', en: 'Failed to load workspace · {{err}}' },
169
+ 'workspace-switch-working': { zh: 'Agent 运行中,无法切换工作区', en: 'Cannot switch workspaces while the agent is running' },
170
+ 'workspace-open-invalid': { zh: '无法打开工作区:{target} 不是存在的目录', en: 'Cannot open workspace: {target} is not an existing directory' },
171
+ 'workspace-switched': { zh: '已切换工作区:{{target}}', en: 'Workspace switched: {{target}}' },
172
+ 'workspace-flow-hint': { zh: '**Enter** 选择 · Esc 退出', en: '**Enter** select · Esc to exit' },
173
+ 'workspace-flow-edit-hint': { zh: '**Enter** 选择当前目录 · Tab 手动输入路径 · Esc 退出', en: '**Enter** select current directory · Tab enter a path · Esc to exit' },
174
+ 'workspace-flow-input-hint': { zh: '输入绝对路径 · **Enter** 读取目录 · Esc 返回', en: 'Enter an absolute path · **Enter** load directory · Esc back' },
175
+ 'workspace-flow-input-empty': { zh: '目录路径不能为空', en: 'Directory path cannot be empty' },
176
+ 'workspace-flow-loading': { zh: '正在连接并读取目录… · Esc 关闭', en: 'Connecting and loading directories… · Esc to close' },
177
+ 'workspace-command-usage': { zh: '用法:/workspace resume | rename <名称> | open <路径或 URI>{{commands}}', en: 'Usage: /workspace resume | rename <name> | open <path-or-URI>{{commands}}' },
178
+ 'workspace-open-usage': { zh: '用法:/workspace open <路径或 URI>', en: 'Usage: /workspace open <path-or-URI>' },
179
+ 'workspace-rename-usage': { zh: '用法:/workspace rename <名称>', en: 'Usage: /workspace rename <name>' },
180
+ 'workspace-command-unknown': { zh: '未知的 workspace 子命令:{{command}}', en: 'Unknown workspace subcommand: {{command}}' },
181
+ 'workspace-command-empty': { zh: '该 workspace 操作没有可选目标', en: 'This workspace action has no available targets' },
182
+ 'workspace-command-failed': { zh: 'workspace 操作失败 · {{err}}', en: 'Workspace action failed · {{err}}' },
183
+ 'workspace-renamed': { zh: '工作区已重命名:{{title}}', en: 'Workspace renamed: {{title}}' },
184
+ 'workspace-rename-failed': { zh: '工作区重命名失败 · {{err}}', en: 'Failed to rename workspace · {{err}}' },
135
185
  'cost-cache-rate': { zh: '缓存率 {{rate}}% · {{read}} 读 / {{write}} 写', en: 'Cache rate {{rate}}% · {{read}} read / {{write}} write' },
136
186
  'cost-context': { zh: '上下文 {{pct}}%', en: 'Context {{pct}}%' },
137
187
  'status-title': { zh: '标题 {{title}}', en: 'Title {{title}}' },
@@ -153,7 +203,8 @@ const dict = {
153
203
  'login-source-hint': { zh: '来源:环境变量 → 工作区 .env(run.ts 兜底读取)', en: 'Source: env var → workspace .env (run.ts fallback)' },
154
204
  'login-logout-hint': { zh: 'DSH 凭证来自环境变量 DEEPSEEK_API_KEY — 删除该环境变量后重启 dsh-tui 即登出', en: 'DSH credentials come from the DEEPSEEK_API_KEY env var — remove it and restart dsh-tui to log out' },
155
205
  'permissions-policy-hint': { zh: 'DSH 权限策略由 fs-policy / bash-sandbox 配置决定(当前 leaf:workspace 内读写、写入需已读文件)。', en: 'DSH permission policy is set by fs-policy / bash-sandbox config (current leaf: read/write in workspace, writes need a prior read).' },
156
- 'permissions-approval-hint': { zh: 'DSH 的 /permission 预设切换需要 approval 服务 + 审批 UI,dsh-tui 未挂载。', en: 'DSH /permission preset switching needs the approval service + approval UI, not mounted in dsh-tui.' },
206
+ 'permissions-approval-hint': { zh: '审批通道已挂载:命令申请权限提升(sandbox_permissions)时弹出审批条,Yes 放行一次、No / Esc 拒绝。', en: 'The approval channel is mounted: sandbox escalations (sandbox_permissions) raise an approval bar — Yes allows once, No / Esc rejects.' },
207
+ 'permissions-preset-hint': { zh: '/permission 可查看与切换权限预设(read-only / workspace-write / danger-full-access)。', en: '/permission shows and switches permission presets (read-only / workspace-write / danger-full-access).' },
157
208
  'permissions-root-hint': { zh: '当前文件系统策略以工作目录为根:{{cwd}}', en: 'Current filesystem policy is rooted at the working directory: {{cwd}}' },
158
209
  'permissions-path-hint': { zh: '模型工具相对路径均解析自该目录;跨目录访问由 fs-policy 拦截。', en: 'Relative paths of model tools resolve from this directory; cross-directory access is blocked by fs-policy.' },
159
210
  'hooks-not-mounted': { zh: 'DSH hooks(dsh-hooks-claude / dsh-hooks-codex)未在本 leaf 挂载。', en: 'DSH hooks (dsh-hooks-claude / dsh-hooks-codex) are not mounted in this leaf.' },
@@ -168,10 +219,28 @@ const dict = {
168
219
  'update-check-failed': { zh: '无法确认新版本(网络或 registry 不可达),已尝试直接更新……', en: 'Could not confirm a newer version (network or registry unreachable); attempting the update anyway…' },
169
220
  'vim-not-implemented': { zh: 'vim 模式暂未实现', en: 'vim mode not implemented yet' },
170
221
  'terminal-setup-hint': { zh: '推荐 Windows Terminal(≥110 列、等宽字体、TrueColor)。', en: 'Recommended: Windows Terminal (≥110 columns, monospace, TrueColor).' },
171
- 'terminal-paste-hint': { zh: '{{mod}}V 粘贴文本/文件路径;Ctrl+Shift+V 终端原生粘贴;右键粘贴同样可用。', en: '{{mod}}V pastes text/file paths; Ctrl+Shift+V is native terminal paste; right-click paste also works.' },
222
+ 'terminal-paste-hint': { zh: '{{mod}}V 粘贴文本、文件路径或图片;Ctrl+Shift+V 终端原生粘贴;右键粘贴同样可用。', en: '{{mod}}V pastes text, file paths, or images; Ctrl+Shift+V is native terminal paste; right-click paste also works.' },
172
223
  'connect-none': { zh: 'DSH 暂无远程连接机制(CC 的 /connect 对应能力未适配)。', en: 'DSH has no remote connection mechanism (CC\'s /connect equivalent is not adapted).' },
173
- 'theme-switch-failed': { zh: '主题「{{name}}」切换失败(无法写入 ~/.dsh-cc/theme.json)', en: 'Theme "{{name}}" switch failed (cannot write ~/.dsh-cc/theme.json)' },
224
+ 'theme-switch-failed': { zh: '主题「{{name}}」切换失败(无法写入 ~/.dsh-tui/theme.json)', en: 'Theme "{{name}}" switch failed (cannot write ~/.dsh-tui/theme.json)' },
174
225
  'interrupt-delivered': { zh: '已打断当前回合,{{n}} 条消息立即处理', en: 'Interrupted current turn, {{n}} messages processed immediately' },
226
+ 'btw-usage': { zh: '用法:/btw <问题> —— 不打断当前对话的快速侧问', en: 'Usage: /btw <question> — quick side question without interrupting the conversation' },
227
+ 'btw-answering': { zh: '思考中…', en: 'Answering…' },
228
+ 'btw-hint-loading': { zh: 'Esc 取消', en: 'Esc cancel' },
229
+ 'btw-hint-done': { zh: '↑/↓ 滚动 · Space/Enter/Esc 关闭 · c 复制', en: '↑/↓ scroll · Space/Enter/Esc dismiss · c copy' },
230
+ 'btw-llm-unavailable': { zh: '侧问不可用(llm 服务未挂载)', en: 'Side question unavailable (llm service not mounted)' },
231
+ 'exit-press-again': { zh: '再次按 Ctrl+C 退出', en: 'Press Ctrl+C again to exit' },
232
+ 'new-session-started': { zh: '已新建会话', en: 'New session started' },
233
+ 'command-not-found': { zh: '/{{name}}:没有这个命令', en: '/{{name}}: no such command' },
234
+ 'thinking-toggled': { zh: '思考模式:{{state}}', en: 'Thinking {{state}}' },
235
+ 'thinking-on': { zh: '开启', en: 'on' },
236
+ 'thinking-off': { zh: '关闭', en: 'off' },
237
+ 'tokens-usage': { zh: 'Tokens:{{in}} 输入 · {{out}} 输出', en: 'Tokens: {{in}} in · {{out}} out' },
238
+ 'tokens-usage-context': { zh: '{{usage}} · 上下文 {{percent}}%', en: '{{usage}} · {{percent}}% of context' },
239
+ // ── plugin.ts — boot-time rename notices (issue #120) ───────────────
240
+ 'legacy-dir-migrated': { zh: '数据目录已从 ~/.dsh-tui 复制到 ~/.dsh-tui(旧目录保留,确认无误后可自行删除)', en: 'Data directory copied from ~/.dsh-tui to ~/.dsh-tui (the old directory is kept; delete it yourself once satisfied)' },
241
+ 'legacy-env-renamed': { zh: '环境变量 {{old}} 已更名为 {{new}},旧名不再生效', en: 'Environment variable {{old}} was renamed to {{new}}; the old name no longer takes effect' },
242
+ // ── plugin.ts — /update flow ───────────────────────────────────────
243
+ 'update-aborted-no-profile': { zh: 'dsh-tui 更新中止:未解析到 dsh profile。', en: 'dsh-tui update aborted: no dsh profile resolved.' },
175
244
  // ── components/ActivityLine.tsx ──────────────────────────────────────
176
245
  'activity-ctx-warn': { zh: '⚠ 上下文', en: '⚠ ctx ' },
177
246
  // ── components/ActivityPicker.tsx ─────────────────────────────────────
@@ -185,11 +254,22 @@ const dict = {
185
254
  'effort-single-tier': { zh: '当前模型只有一档推理等级({{name}})', en: 'Current model has a single reasoning effort ({{name}})' },
186
255
  'effort-unsupported': { zh: '当前模型不支持推理等级切换', en: 'Current model does not support reasoning effort switching' },
187
256
  'effort-switched': { zh: '推理强度 → {{name}}', en: 'Reasoning effort → {{name}}' },
257
+ 'effort-invalid': { zh: '未知推理等级 {{id}}(当前模型可选:{{ids}})', en: 'Unknown reasoning effort {{id}} (this model offers: {{ids}})' },
258
+ 'effort-current': { zh: '当前推理强度 {{name}}', en: 'Current reasoning effort {{name}}' },
259
+ 'effort-usage': { zh: '用法:/effort(滑杆)| /effort <id> | /effort status', en: 'Usage: /effort (slider) | /effort <id> | /effort status' },
260
+ // ── channel.ts — Shift+Tab session modes ────────────────────────────
261
+ 'mode-switched': { zh: '模式 → {{name}}', en: 'Mode → {{name}}' },
262
+ 'mode-default': { zh: '默认', en: 'default' },
263
+ 'mode-plan': { zh: '计划模式', en: 'plan mode' },
264
+ 'mode-full': { zh: '完全访问', en: 'full access' },
265
+ 'mode-plan-unavailable': { zh: '当前 preset 未注册 /plan 命令,无法切换计划模式', en: 'The active preset does not register /plan; cannot toggle plan mode' },
188
266
  // ── components/LogoV2.tsx ───────────────────────────────────────────
189
267
  'logo-tagline': { zh: '探索未至之境!', en: 'Explore the uncharted!' },
190
268
  'logo-tip-model': { zh: '切换模型', en: 'switch model' },
191
269
  'logo-tip-help': { zh: '查看命令', en: 'view commands' },
192
270
  'logo-tip-tab': { zh: '自动补全', en: 'autocomplete' },
271
+ 'logo-tip-trace': { zh: '会话轨迹', en: 'trajectory' },
272
+ 'logo-tip-prefix': { zh: '提示:', en: 'Tip: ' },
193
273
  // ── components/PromptInput.tsx ──────────────────────────────────────
194
274
  'input-sent-after-turn': { zh: '已发送,当前回合结束后处理', en: 'Sent, processed after the current turn' },
195
275
  'input-interrupted-next': { zh: '已插话 · 下一步立即处理', en: 'Interrupted · processed next' },
@@ -199,6 +279,13 @@ const dict = {
199
279
  'input-empty': { zh: '输入为空,没有可发送的内容', en: 'Empty input, nothing to send' },
200
280
  'input-interrupt-immediate': { zh: '已打断当前回合,正在立即处理', en: 'Interrupted current turn, processing immediately' },
201
281
  'input-clipboard-empty': { zh: '剪贴板为空', en: 'Clipboard is empty' },
282
+ 'input-editor-unavailable': { zh: '未找到可用编辑器,请设置 $EDITOR(或 $VISUAL)环境变量', en: 'No editor available — set the $EDITOR (or $VISUAL) environment variable' },
283
+ 'input-editor-failed': { zh: '外部编辑器失败:{{name}}', en: 'External editor failed: {{name}}' },
284
+ 'input-clipboard-read-failed': { zh: '读取剪贴板失败', en: 'Failed to read the clipboard' },
285
+ 'input-clipboard-unavailable': { zh: '无法读取剪贴板:没有可用的 wl-paste / xclip / xsel(未安装或会话不可连接)', en: 'Cannot read clipboard: no usable wl-paste / xclip / xsel (not installed or session unreachable)' },
286
+ 'input-clipboard-image-saved': { zh: '剪贴板图片已保存为临时文件,已插入路径', en: 'Clipboard image saved to a temp file; path inserted' },
287
+ 'input-image-pasted': { zh: '已粘贴图片 {{token}}', en: 'Pasted image {{token}}' },
288
+ 'input-image-paste-failed': { zh: '粘贴图片失败:{{err}}', en: 'Could not paste image: {{err}}' },
202
289
  'input-pending-steer-label': { zh: '插话 · 下一步送达', en: 'Steer · delivered next' },
203
290
  'input-pending-queue-label': { zh: '排队 · 回合结束后送达', en: 'Queued · delivered after the turn' },
204
291
  'input-pending-actions-hint': { zh: '撤回 · Esc 打断并立即发送', en: 'Retract · Esc interrupts and sends immediately' },
@@ -215,16 +302,99 @@ const dict = {
215
302
  'frame-tail-1': { zh: '摆尾巴1', en: 'tail1' },
216
303
  'frame-tail-2': { zh: '摆尾巴2', en: 'tail2' },
217
304
  'frame-tail-3': { zh: '摆尾巴3', en: 'tail3' },
305
+ // ── components/HelpMenu.tsx ─────────────────────────────────────────
306
+ 'help-for-commands': { zh: '/ 查看命令', en: '/ for commands' },
307
+ 'help-this-help': { zh: '? 查看本帮助', en: '? for this help' },
308
+ 'help-verbose-output': { zh: '{{mod}}o 详细输出', en: '{{mod}}o for verbose output' },
309
+ 'help-toggle-context': { zh: '{{mod}}t 切换上下文', en: '{{mod}}t to toggle context' },
310
+ 'help-search-history': { zh: '{{mod}}r 搜索历史', en: '{{mod}}r to search history' },
311
+ 'help-interrupt': { zh: 'ctrl+c 打断', en: 'ctrl+c to interrupt' },
312
+ 'help-exit': { zh: 'ctrl+d 退出', en: 'ctrl+d to exit' },
313
+ 'help-redraw': { zh: '{{mod}}l 重绘', en: '{{mod}}l to redraw' },
314
+ 'help-clear-input': { zh: 'esc 清空输入', en: 'esc to clear input' },
315
+ 'help-history-nav': { zh: '↑/↓ 历史', en: '↑/↓ for history' },
316
+ 'help-move-cursor': { zh: '←/→ 移动光标', en: '←/→ to move cursor' },
317
+ 'help-word-jumps': { zh: '{{mod}}←/→ 按词跳转', en: '{{mod}}←/→ for word jumps' },
318
+ 'help-complete-command': { zh: 'tab 补全命令', en: 'tab to complete command' },
319
+ 'help-cycle-mode': { zh: 'shift+tab 切换模式', en: 'shift+tab to cycle mode' },
320
+ 'help-open-editor': { zh: 'ctrl+x 打开编辑器', en: 'ctrl+x to open editor' },
321
+ 'help-commands-title': { zh: '命令:', en: 'commands:' },
322
+ // ── components/InterruptedByUser.tsx ────────────────────────────────
323
+ 'interrupted-by-user': { zh: '已打断 ', en: 'Interrupted ' },
324
+ 'interrupted-ask-next': { zh: '· 接下来想让 DeepSeek 做什么?', en: '· What should DeepSeek do instead?' },
218
325
  // ── components/MessageList.tsx ──────────────────────────────────────
219
326
  'load-earlier': { zh: ' ↑ 加载更早消息(会话日志完整,/export 导出全文) ', en: ' ↑ load earlier messages (full session log; /export for full text) ' },
327
+ 'show-previous-messages': { zh: ' ctrl+e 显示前 {{n}} 条消息 ', en: ' ctrl+e to show {{n}} previous messages ' },
220
328
  'resume-none-in-cwd': { zh: '当前目录没有可恢复的历史会话', en: 'No resumable sessions in the current directory' },
329
+ // ── components/ResumePicker.tsx + screens/Chat.tsx (/resume) ────────
330
+ 'resume-resumed': { zh: '已恢复会话', en: 'Session resumed' },
331
+ 'resume-more-above': { zh: '↑ 还有 {{n}} 条', en: '↑ {{n}} more' },
332
+ 'resume-more-below': { zh: '↓ 还有 {{n}} 条', en: '↓ {{n}} more' },
333
+ 'resume-delete-confirm': { zh: '删除「{{name}}」?会话日志将被永久移除。', en: 'Delete "{{name}}"? The session log is removed permanently.' },
334
+ 'resume-deleted': { zh: '已删除会话「{{name}}」', en: 'Deleted session {{name}}' },
335
+ 'resume-delete-failed': { zh: '无法删除会话「{{name}}」', en: 'Could not delete session {{name}}' },
336
+ 'resume-rename-placeholder': { zh: '新的会话名称…', en: 'New session name…' },
337
+ 'resume-rename-failed': { zh: '无法重命名会话「{{name}}」', en: 'Could not rename session {{name}}' },
338
+ 'resume-hint-list': { zh: '**Enter** 恢复 · Esc 退出 · {{mod}}d 删除 · {{mod}}r 重命名', en: '**Enter** to confirm · Esc to exit · {{mod}}d to delete · {{mod}}r to rename' },
339
+ 'resume-hint-delete': { zh: '**Enter** 删除 · Esc 取消', en: '**Enter** to delete · Esc to cancel' },
340
+ 'resume-hint-rename': { zh: '**Enter** 保存 · Esc 取消', en: '**Enter** to save · Esc to cancel' },
341
+ 'resume-title': { zh: '恢复会话', en: 'Resume' },
342
+ // ── picker 通用快捷键提示(整句本地化,zh 不用 "to" 结构;**段** 渲染为粗体主快捷键)─
343
+ 'hint-confirm-exit': { zh: '**Enter** 确认 · Esc 退出', en: '**Enter** to confirm · Esc to exit' },
344
+ 'hint-confirm-cancel': { zh: '**Enter** 确认 · Esc 取消', en: '**Enter** to confirm · Esc to cancel' },
345
+ 'hint-select-exit': { zh: '**Enter** 选择 · Esc 退出', en: '**Enter** to select · Esc to exit' },
346
+ 'hint-rewind-back': { zh: '**Enter** 回退 · Esc 返回', en: '**Enter** to rewind · Esc to back' },
347
+ 'hint-adjust-done': { zh: '**←/→** 调整 · Enter/Esc 完成', en: '**←/→** to adjust · Enter/Esc to done' },
348
+ 'hint-history-search': { zh: '↑/↓ 选择 · **Enter** 确认 · Esc 取消', en: '↑/↓ to navigate · **Enter** to select · Esc to cancel' },
349
+ 'hint-expand-ctrl-o': { zh: '(ctrl+o 展开)', en: '(ctrl+o to expand)' },
350
+ // ── components/ModelPicker.tsx / ThemePicker.tsx / ActivityPicker.tsx / EffortSlider.tsx ──
351
+ 'picker-title-model': { zh: '模型', en: 'Model' },
352
+ 'picker-title-theme': { zh: '颜色主题', en: 'Color theme' },
353
+ 'picker-title-activity': { zh: '指示器预设', en: 'Indicator preset' },
354
+ 'picker-title-effort': { zh: '推理强度', en: 'Reasoning effort' },
355
+ 'model-loading': { zh: '正在加载模型', en: 'Loading models' },
356
+ 'model-loading-subtitle': { zh: '正在查询 provider…', en: 'Querying the provider…' },
357
+ 'model-switching': { zh: '正在切换模型到 {{name}}…', en: 'Switching model to {{name}}…' },
358
+ 'model-switched': { zh: '模型已切换为 {{name}}', en: 'Model switched to {{name}}' },
359
+ // ── components/RewindPicker.tsx ─────────────────────────────────────
360
+ 'rewind-title': { zh: '回退', en: 'Rewind' },
361
+ 'rewind-subtitle': { zh: '选择一条消息,将对话回退到该处', en: 'Pick a message to rewind the conversation to' },
362
+ 'rewind-confirm-title': { zh: '将对话回退到这条消息?', en: 'Rewind conversation to this message?' },
363
+ 'rewind-confirm-desc': { zh: '对话从此处重新开始', en: 'conversation restarts here' },
364
+ 'rewind-empty': { zh: '没有可回退的消息', en: 'No messages to rewind to' },
365
+ 'rewind-last-message': { zh: '最近一条消息', en: 'last message' },
366
+ 'rewind-none': { zh: '还没有可回退的消息', en: 'Nothing to rewind yet' },
367
+ 'rewind-done': { zh: '已回退——编辑后按 Enter 重新发送', en: 'Rewound — edit and press Enter to resend' },
368
+ // ── components/ThinkingToggle.tsx + messages/AssistantThinkingMessage.tsx ──
369
+ 'thinking-title': { zh: '切换思考模式', en: 'Toggle thinking mode' },
370
+ 'thinking-subtitle': { zh: '为本会话启用或关闭思考。', en: 'Enable or disable thinking for this session.' },
371
+ 'thinking-enabled': { zh: '启用', en: 'Enabled' },
372
+ 'thinking-enabled-desc': { zh: 'DeepSeek 会在回复前先思考', en: 'DeepSeek will think before responding' },
373
+ 'thinking-disabled': { zh: '关闭', en: 'Disabled' },
374
+ 'thinking-disabled-desc': { zh: 'DeepSeek 不做扩展思考,直接回复', en: 'DeepSeek will respond without extended thinking' },
375
+ 'thinking-mid-warning': { zh: '在对话中途切换思考模式会增加延迟,并可能降低质量。建议在会话开始时设置。', en: 'Changing thinking mode mid-conversation will increase latency and may reduce quality. For best results, set this at the start of a session.' },
376
+ 'thinking-proceed': { zh: '要继续吗?', en: 'Do you want to proceed?' },
377
+ 'thinking-label': { zh: '思考', en: 'Thinking' },
378
+ // ── components/HistorySearchDialog.tsx ──────────────────────────────
379
+ 'history-search-title': { zh: '搜索历史', en: 'Search history' },
380
+ 'history-search-placeholder': { zh: '输入以搜索…', en: 'Type to search…' },
381
+ 'history-search-empty': { zh: '没有匹配的命令', en: 'No matching commands' },
382
+ 'time-now': { zh: '刚刚', en: 'now' },
383
+ 'time-minutes-ago': { zh: '{{n}} 分钟前', en: '{{n}}m ago' },
384
+ 'time-hours-ago': { zh: '{{n}} 小时前', en: '{{n}}h ago' },
385
+ 'time-days-ago': { zh: '{{n}} 天前', en: '{{n}}d ago' },
386
+ // ── screens/Chat.tsx(/ 转录搜索条)─────────────────────────────────
387
+ 'search-no-matches': { zh: '无匹配', en: 'no matches' },
221
388
  'rename-usage': { zh: '用法 /rename <新名称>', en: 'Usage /rename <new title>' },
222
389
  'rename-current': { zh: '当前名称 {{title}}', en: 'Current title {{title}}' },
223
390
  'rename-done': { zh: '已重命名为「{{title}}」', en: 'Renamed to "{{title}}"' },
224
391
  'compact-summary-folded': { zh: '摘要已折叠', en: 'Summary folded' },
392
+ 'new-message': { zh: '{{n}} 条新消息', en: '1 new message' },
393
+ 'new-messages': { zh: '{{n}} 条新消息', en: '{{n}} new messages' },
225
394
  // ── components/ThemePicker.tsx ──────────────────────────────────────
226
395
  'theme-builtin-base': { zh: '内置 · {{name}} 基底', en: 'Built-in · {{name}} base' },
227
- 'theme-user-base': { zh: '{{base}} 基底 · ~/.dsh-cc/themes/{{name}}.json', en: '{{base}} base · ~/.dsh-cc/themes/{{name}}.json' },
396
+ 'theme-auto-base': { zh: '内置 · 跟随系统/终端背景自动选择 light/dark', en: 'Built-in · follows the system/terminal background (light/dark)' },
397
+ 'theme-user-base': { zh: '{{base}} 基底 · ~/.dsh-tui/themes/{{name}}.json', en: '{{base}} base · ~/.dsh-tui/themes/{{name}}.json' },
228
398
  // ── components/LoadedContextPanel.tsx ───────────────────────────────
229
399
  'context-panel-collapse': { zh: '折叠', en: 'Collapse' },
230
400
  'context-panel-expand': { zh: '展开', en: 'Expand' },
@@ -261,6 +431,54 @@ const dict = {
261
431
  'plan-review-feedback-placeholder': { zh: '输入反馈,告诉模型要改什么…', en: 'Tell the model what to change…' },
262
432
  'plan-review-approve-needs-empty': { zh: '请先清空反馈再批准(或在输入行回车提交反馈)', en: 'Clear the feedback to approve (or press Enter on the input row to send it)' },
263
433
  'plan-review-hint': { zh: '↑/↓ 选择 · 1/2 快选 · 打字输入反馈 · Enter 提交 · Esc 打断评审', en: '↑/↓ select · 1/2 quick-pick · type feedback · Enter submit · Esc dismiss' },
434
+ // ── providerWizard.ts ────────────────────────────────────────────────
435
+ 'provider-unavailable': { zh: '/provider 需要经 dsh profile 启动(settings / credentials / llm-pi-ai 服务未挂载)', en: '/provider requires starting through a dsh profile (settings / credentials / llm-pi-ai services not mounted)' },
436
+ 'provider-q-mode': { zh: '要添加哪种模型提供方?', en: 'Which kind of model provider do you want to add?' },
437
+ 'provider-opt-catalog': { zh: '内置 provider', en: 'Built-in provider' },
438
+ 'provider-opt-catalog-desc': { zh: 'openai、anthropic、deepseek 等内置目录,自动继承端点与协议', en: 'Built-in catalog such as openai, anthropic, deepseek — endpoint and protocol inherited' },
439
+ 'provider-opt-custom': { zh: '自定义 API 端点', en: 'Custom API endpoint' },
440
+ 'provider-opt-custom-desc': { zh: 'OpenAI / Anthropic 兼容的网关或自建服务', en: 'An OpenAI/Anthropic-compatible gateway or self-hosted server' },
441
+ 'provider-q-catalog': { zh: '选择 provider', en: 'Choose a provider' },
442
+ 'provider-opt-other-route': { zh: '其他(手动输入路由名)', en: 'Other (enter a route name)' },
443
+ 'provider-opt-other-route-desc': { zh: '目录里没列出的 catalog 路由', en: 'A catalog route not listed above' },
444
+ 'provider-q-route-id': { zh: '输入路由名', en: 'Enter a route name' },
445
+ 'provider-q-route-id-detail': { zh: '小写字母开头,可含数字与连字符,如 my-gateway', en: 'Lowercase letter first, digits and dashes allowed, e.g. my-gateway' },
446
+ 'provider-route-id-invalid': { zh: '路由名不合法:须以小写字母开头,仅含小写字母 / 数字 / 连字符', en: 'Invalid route name: must start with a lowercase letter, only lowercase letters / digits / dashes' },
447
+ 'provider-q-apikey': { zh: '输入 API key', en: 'Enter the API key' },
448
+ 'provider-q-apikey-detail': { zh: '密钥将写入 ~/.dsh/.credentials.yaml(权限 0600),不会出现在会话记录中', en: 'The key is stored in ~/.dsh/.credentials.yaml (mode 0600) and never shown in the transcript' },
449
+ 'provider-q-baseurl-choice': { zh: '是否覆盖默认 API 端点(baseURL)?', en: 'Override the default API endpoint (baseURL)?' },
450
+ 'provider-opt-baseurl-skip': { zh: '跳过,使用默认端点', en: 'Skip — use the default endpoint' },
451
+ 'provider-opt-baseurl-input': { zh: '现在输入 baseURL', en: 'Enter a baseURL now' },
452
+ 'provider-q-baseurl': { zh: '输入 baseURL', en: 'Enter the baseURL' },
453
+ 'provider-q-protocol': { zh: '选择 API 协议', en: 'Choose the wire protocol' },
454
+ 'provider-protocol-completions-desc': { zh: 'OpenAI Chat Completions 兼容(大多数网关)', en: 'OpenAI Chat Completions compatible (most gateways)' },
455
+ 'provider-protocol-responses-desc': { zh: 'OpenAI Responses API', en: 'OpenAI Responses API' },
456
+ 'provider-protocol-anthropic-desc': { zh: 'Anthropic Messages API', en: 'Anthropic Messages API' },
457
+ 'provider-discovery-running': { zh: '正在探测该端点公布的模型…', en: 'Discovering the models this endpoint advertises…' },
458
+ 'provider-discovery-failed': { zh: '模型探测失败,改为手动输入模型 id', en: 'Model discovery failed — enter model ids manually instead' },
459
+ 'provider-q-models': { zh: '选择要启用的模型(可在输入行逗号分隔补充)', en: 'Select the models to enable (add more comma-separated on the input row)' },
460
+ 'provider-q-models-fallback': { zh: '输入模型 id(逗号分隔)', en: 'Enter model ids (comma-separated)' },
461
+ 'provider-models-required': { zh: '自定义端点至少需要一个模型 id', en: 'A custom endpoint needs at least one model id' },
462
+ 'provider-q-confirm': { zh: '确认写入该 provider 配置?', en: 'Write this provider configuration?' },
463
+ 'provider-route-exists-warning': { zh: '⚠ 该路由已有配置,写入将覆盖现有设置', en: '⚠ This route is already configured — writing overwrites it' },
464
+ 'provider-opt-confirm-write': { zh: '写入并启用', en: 'Write and enable' },
465
+ 'provider-opt-confirm-cancel': { zh: '取消', en: 'Cancel' },
466
+ 'provider-line-route': { zh: '路由:{{route}}', en: 'Route: {{route}}' },
467
+ 'provider-line-keyref': { zh: '密钥引用:{{ref}}(已写入 ~/.dsh/.credentials.yaml)', en: 'Key ref: {{ref}} (stored in ~/.dsh/.credentials.yaml)' },
468
+ 'provider-line-keyref-env': { zh: '密钥引用:{{ref}}(进程环境已提供同名变量,跳过写入)', en: 'Key ref: {{ref}} (already in the process environment, write skipped)' },
469
+ 'provider-line-baseurl': { zh: 'baseURL:{{url}}', en: 'baseURL: {{url}}' },
470
+ 'provider-line-protocol': { zh: '协议:{{api}}', en: 'Protocol: {{api}}' },
471
+ 'provider-line-models': { zh: '模型:{{models}}', en: 'Models: {{models}}' },
472
+ 'provider-line-models-catalog': { zh: '模型:整个 catalog(未收窄)', en: 'Models: the whole catalog (not narrowed)' },
473
+ 'provider-rollback-ok': { zh: '已回滚刚写入的密钥', en: 'Rolled back the just-written key' },
474
+ 'provider-rollback-failed': { zh: '密钥回滚失败,请手动检查 ~/.dsh/.credentials.yaml', en: 'Key rollback failed — check ~/.dsh/.credentials.yaml manually' },
475
+ 'provider-write-failed': { zh: 'provider 配置写入失败 · {{err}}', en: 'Failed to write the provider configuration · {{err}}' },
476
+ 'provider-cancelled': { zh: '已取消添加 provider', en: 'Provider setup cancelled' },
477
+ 'provider-success': { zh: 'provider {{route}} 已添加', en: 'Provider {{route}} added' },
478
+ 'provider-switch-hint': { zh: '运行 /model 可切换到新 provider 的模型', en: 'Run /model to switch to the new provider’s models' },
479
+ 'provider-q-switch': { zh: '立即切换到新 provider?', en: 'Switch to the new provider now?' },
480
+ 'provider-opt-switch-now': { zh: '切换到 {{model}}', en: 'Switch to {{model}}' },
481
+ 'provider-opt-switch-keep': { zh: '保持当前模型', en: 'Keep the current model' },
264
482
  // ── commands.ts — slash-command descriptions ─────────────────────────
265
483
  // zh-only on purpose: the English text stays in `LOCAL_COMMANDS` (and in
266
484
  // the DSH registry for external commands) as the single source of truth,
@@ -273,24 +491,27 @@ const dict = {
273
491
  'cmd-desc-compact': { zh: '压缩会话历史' },
274
492
  'cmd-desc-resume': { zh: '恢复历史会话' },
275
493
  'cmd-desc-rename': { zh: '重命名当前会话' },
494
+ 'cmd-desc-quit': { zh: '退出 dsh-tui' },
495
+ 'cmd-desc-q': { zh: '退出 dsh-tui' },
276
496
  'cmd-desc-rewind': { zh: '回退会话到历史消息' },
277
497
  'cmd-desc-export': { zh: '导出会话为 Markdown 文件' },
278
498
  // Session / environment
279
499
  'cmd-desc-status': { zh: '查看会话状态' },
280
500
  'cmd-desc-cost': { zh: '查看会话 token 用量' },
281
- 'cmd-desc-config': { zh: '查看 dsh-cc 配置来源' },
501
+ 'cmd-desc-config': { zh: '查看 dsh-tui 配置来源' },
282
502
  'cmd-desc-doctor': { zh: '运行环境检查' },
283
503
  'cmd-desc-init': { zh: '在工作目录创建 AGENTS.md' },
284
504
  'cmd-desc-agents': { zh: '查看本会话的子代理' },
285
505
  // Model / display
286
506
  'cmd-desc-activity': { zh: '切换工作状态指示器预设' },
287
507
  'cmd-desc-preset': { zh: '切换 Agent 预设(standard/code/minimal/cordis)' },
288
- 'cmd-desc-theme': { zh: '切换配色主题(内置或自定义)' },
508
+ 'cmd-desc-theme': { zh: '切换配色主题(auto 跟随系统,或内置/自定义)' },
289
509
  'cmd-desc-lang': { zh: '切换界面语言(en / zh)' },
290
510
  'cmd-desc-model': { zh: '查看当前模型' },
291
511
  'cmd-desc-thinking': { zh: '切换扩展思考显示' },
292
512
  'cmd-desc-tokens': { zh: '查看会话 token 用量' },
293
513
  // Account / policy
514
+ 'cmd-desc-provider': { zh: '添加模型提供方(内置目录或自定义 API 端点)' },
294
515
  'cmd-desc-login': { zh: '查看 API 凭证状态' },
295
516
  'cmd-desc-logout': { zh: '清除 API 凭证' },
296
517
  'cmd-desc-permissions': { zh: '查看权限策略状态' },
@@ -298,11 +519,11 @@ const dict = {
298
519
  'cmd-desc-hooks': { zh: '查看 hooks 状态' },
299
520
  'cmd-desc-mcp': { zh: '查看 MCP 状态' },
300
521
  'cmd-desc-memory': { zh: '查看记忆状态' },
301
- 'cmd-desc-update': { zh: '更新 dsh-cc-tui 并重启' },
522
+ 'cmd-desc-update': { zh: '更新 dsh-tui 并重启' },
302
523
  // Built-in skills
303
524
  'cmd-desc-audit': { zh: '对当前项目做全面代码审计' },
304
525
  'cmd-desc-bug': { zh: '记录一份 bug 报告' },
305
- 'cmd-desc-practice': { zh: '与 dsh-cc 进行编程练习' },
526
+ 'cmd-desc-practice': { zh: '与 dsh-tui 进行编程练习' },
306
527
  'cmd-desc-review': { zh: '对当前项目做全面代码评审' },
307
528
  'cmd-desc-pr_comments': { zh: '审查拉取请求评论' },
308
529
  'cmd-desc-release-notes': { zh: '生成发布说明' },
@@ -311,6 +532,10 @@ const dict = {
311
532
  'cmd-desc-vim': { zh: '切换 vim 模式' },
312
533
  'cmd-desc-terminal-setup': { zh: '查看终端配置建议' },
313
534
  'cmd-desc-connect': { zh: '连接远程机器' },
535
+ 'cmd-desc-workspace': { zh: '切换、重命名或打开工作区' },
536
+ 'cmd-desc-workspace-resume': { zh: '切换到另一个工作区', en: 'Switch to another workspace' },
537
+ 'cmd-desc-workspace-rename': { zh: '重命名当前工作区', en: 'Rename the current workspace' },
538
+ 'cmd-desc-workspace-open': { zh: '打开路径或工作区 URI', en: 'Open a path or workspace URI' },
314
539
  // Help / exit
315
540
  'cmd-desc-help': { zh: '查看快捷键与命令' },
316
541
  'cmd-desc-exit': { zh: '退出 dsh-tui' },
@@ -322,15 +547,55 @@ const dict = {
322
547
  // ── /lang command ───────────────────────────────────────────────────
323
548
  'lang-current': { zh: '当前语言 {{lang}}', en: 'Current language {{lang}}' },
324
549
  'lang-switch-hint': { zh: '切换 /lang en | /lang zh', en: 'Switch /lang en | /lang zh' },
325
- 'lang-persist-hint': { zh: '持久化 ~/.dsh-cc/lang.json(重启后仍生效;CC_TUI_LANG 优先)', en: 'Persisted ~/.dsh-cc/lang.json (survives restart; CC_TUI_LANG wins)' },
550
+ 'lang-persist-hint': { zh: '持久化 ~/.dsh-tui/lang.json(重启后仍生效;DSH_TUI_LANG 优先)', en: 'Persisted ~/.dsh-tui/lang.json (survives restart; DSH_TUI_LANG wins)' },
326
551
  'lang-switched': { zh: '语言已切换:{{lang}}(已保存)', en: 'Language switched: {{lang}} (saved)' },
327
552
  'lang-unknown': { zh: '未知语言「{{lang}}」· /lang 查看全部(en / zh)', en: 'Unknown language "{{lang}}" · /lang to view all (en / zh)' },
328
- 'lang-switch-failed': { zh: '语言「{{lang}}」切换失败(无法写入 ~/.dsh-cc/lang.json)', en: 'Language "{{lang}}" switch failed (cannot write ~/.dsh-cc/lang.json)' },
553
+ 'lang-switch-failed': { zh: '语言「{{lang}}」切换失败(无法写入 ~/.dsh-tui/lang.json)', en: 'Language "{{lang}}" switch failed (cannot write ~/.dsh-tui/lang.json)' },
554
+ // ── screens/StatusLine.tsx ───────────────────────────────────────────
555
+ 'status-cache-label': { zh: '缓存 ', en: 'cache ' },
556
+ // ── screens/TrajectoryScene.tsx(issue #80 演进:全屏轨迹场景)──────────
557
+ 'traj-title': { zh: '轨迹', en: 'Trajectory' },
558
+ 'traj-totals': { zh: '{{turns}} 轮 · {{steps}} 步', en: '{{turns}} turns · {{steps}} rows' },
559
+ 'traj-errors': { zh: '{{n}} 错', en: '{{n}} failed' },
560
+ 'traj-retries': { zh: '{{n}} 重试', en: '{{n}} retries' },
561
+ 'traj-matches': { zh: '{{n}}/{{total}} 匹配', en: '{{n}}/{{total}} matched' },
562
+ 'traj-tab-timeline': { zh: '时序', en: 'Timeline' },
563
+ 'traj-tab-hotspot': { zh: '热点', en: 'Hotspot' },
564
+ 'traj-hot-tools': { zh: '工具', en: 'Tools' },
565
+ 'traj-hot-model': { zh: '模型', en: 'Model' },
566
+ 'traj-hot-turns': { zh: '轮次', en: 'Turns' },
567
+ 'traj-sort-duration': { zh: '按耗时', en: 'by duration' },
568
+ 'traj-sort-count': { zh: '按次数', en: 'by count' },
569
+ 'traj-sort-tokens': { zh: '按 token', en: 'by tokens' },
570
+ 'traj-proj-sequence': { zh: '序号等宽', en: 'even' },
571
+ 'traj-proj-time': { zh: '真实墙钟', en: 'wall-clock' },
572
+ 'traj-proj-compressed': { zh: '压缩空闲', en: 'compressed' },
573
+ 'traj-hint-timeline': {
574
+ zh: '**↑/↓** 移动 · **←/→** 视图 · **[ ]** 跳错 · **{ }** 跳轮 · **/** 查询 · **m** 投影 · **enter** 详情 · **q** 退出',
575
+ en: '**↑/↓** move · **←/→** view · **[ ]** failures · **{ }** turns · **/** query · **m** projection · **enter** detail · **q** exit',
576
+ },
577
+ 'traj-hint-hotspot': {
578
+ zh: '**↑/↓** 移动 · **←/→** 视图 · **t** 排序 · **enter** 回时序定位 · **q** 退出',
579
+ en: '**↑/↓** move · **←/→** view · **t** sort · **enter** locate in timeline · **q** exit',
580
+ },
581
+ 'traj-hint-query': {
582
+ zh: '**tool:** **kind:** **turn:** **err:** **run:** **>10s** **tok>1k** · 裸词全文 · **enter** 确认 · **esc** 清除',
583
+ en: '**tool:** **kind:** **turn:** **err:** **run:** **>10s** **tok>1k** · bare word = full text · **enter** apply · **esc** clear',
584
+ },
585
+ 'traj-hint-expanded': {
586
+ zh: '**j/k** 翻页 · **enter/esc** 收起 · **q** 退出',
587
+ en: '**j/k** page · **enter/esc** collapse · **q** exit',
588
+ },
589
+ 'traj-empty': { zh: '暂无轨迹事件', en: 'No trajectory events yet' },
590
+ 'traj-hint-failure': { zh: '{{key}} 看完整轨迹', en: '{{key}} for the full trajectory' },
329
591
  };
330
592
  /** The active language, module-level so non-React modules (channel.ts,
331
593
  * loaded-context.ts) resolve strings without a context. Defaults to `zh`
332
594
  * (the original hard-coded language). */
333
- let activeLang = 'zh';
595
+ // Resolved at import time (env var → persisted /lang → OS locale → zh) so
596
+ // direct consumers of t() — repro/verify scripts that never reach
597
+ // plugin.apply — still get the pinned language instead of a hardcoded zh.
598
+ let activeLang = resolveStartupLang();
334
599
  const listeners = new Set();
335
600
  /** Subscribe to language switches (mirrors themePrefs subscription style). */
336
601
  export function subscribeLang(listener) {
@@ -376,7 +641,7 @@ export function tOr(key, fallback) {
376
641
  const entry = dict[key];
377
642
  return entry?.[activeLang] ?? fallback;
378
643
  }
379
- // ── persistence (~/.dsh-cc/lang.json) ──────────────────────────────────
644
+ // ── persistence (~/.dsh-tui/lang.json) ─────────────────────────────────
380
645
  /**
381
646
  * Parse a persisted `{ lang }` value; anything else yields undefined.
382
647
  * @param text - Raw file contents.
@@ -417,25 +682,37 @@ export function writeLangPref(lang, dir = PREFS_DIR) {
417
682
  * Guess the user's language from the OS locale (`LC_ALL`, `LC_MESSAGES`,
418
683
  * `LANG`), defaulting to `zh`. Only consulted when nothing else (env var,
419
684
  * cordis.yml `lang`, persisted `/lang` choice) pinned a language.
685
+ * The POSIX/C locale means "no locale selected" and conventionally maps to
686
+ * English — importantly it is what CI runners (LANG=C.UTF-8) report, so
687
+ * tests asserting English UI copy stay deterministic. An absent locale
688
+ * variable (typical on Windows) still defaults to `zh`.
420
689
  */
421
690
  export function detectLocaleLang() {
422
- const raw = process.env.LC_ALL ??
423
- process.env.LC_MESSAGES ??
424
- process.env.LANG ??
691
+ // `||` (not `??`): an EMPTY locale variable means "unset" and must fall
692
+ // through to the next one — runners and shells sometimes export LC_ALL=''.
693
+ const raw = process.env.LC_ALL ||
694
+ process.env.LC_MESSAGES ||
695
+ process.env.LANG ||
425
696
  '';
426
697
  const locale = raw.split('.')[0]?.toLowerCase() ?? '';
427
698
  if (locale.startsWith('zh'))
428
699
  return 'zh';
429
700
  if (locale.startsWith('en'))
430
701
  return 'en';
702
+ if (locale === 'c' || locale === 'posix')
703
+ return 'en';
431
704
  return 'zh';
432
705
  }
433
706
  /**
434
- * Resolve the startup language: the persisted `/lang` choice, else the OS
435
- * locale guess, else `zh` (the original hard-coded language). The env var /
436
- * config precedence lives in plugin.apply (see {@link resolveStartupLang}
437
- * consumers).
707
+ * Resolve the startup language: `DSH_TUI_LANG` when it holds a valid value
708
+ * (pinned at process start — the repro/verify scripts rely on this for
709
+ * deterministic UI copy), else the persisted `/lang` choice, else the OS
710
+ * locale guess, else `zh` (the original hard-coded language). The
711
+ * cordis.yml `lang` precedence lives in plugin.apply.
438
712
  */
439
713
  export function resolveStartupLang() {
714
+ const envLang = process.env.DSH_TUI_LANG;
715
+ if (isLang(envLang))
716
+ return envLang;
440
717
  return readLangPref() ?? detectLocaleLang();
441
718
  }