@deepseek-harness-tui/dsh-tui 0.8.8 → 0.9.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 (215) hide show
  1. package/README.md +27 -8
  2. package/bin/dsh-tui.js +1 -1
  3. package/lib/types/commands.d.ts.map +1 -1
  4. package/lib/types/commands.js +4 -2
  5. package/lib/types/components/ActivityPicker.d.ts +4 -1
  6. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  7. package/lib/types/components/ActivityPicker.js +2 -2
  8. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  9. package/lib/types/components/BtwPanel.js +1 -1
  10. package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
  11. package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
  12. package/lib/types/components/Chat/SubagentMessage.js +11 -3
  13. package/lib/types/components/CommandSuggestions.d.ts +21 -4
  14. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  15. package/lib/types/components/CommandSuggestions.js +41 -14
  16. package/lib/types/components/EffortSlider.d.ts +4 -1
  17. package/lib/types/components/EffortSlider.d.ts.map +1 -1
  18. package/lib/types/components/EffortSlider.js +4 -2
  19. package/lib/types/components/ExtensionDialog.js +6 -2
  20. package/lib/types/components/FileSuggestions.d.ts +24 -7
  21. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  22. package/lib/types/components/FileSuggestions.js +39 -12
  23. package/lib/types/components/GoalTodoPanel.d.ts +26 -2
  24. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  25. package/lib/types/components/GoalTodoPanel.js +86 -17
  26. package/lib/types/components/HelpMenu.d.ts +7 -1
  27. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  28. package/lib/types/components/HelpMenu.js +12 -4
  29. package/lib/types/components/HistorySearchDialog.d.ts +4 -1
  30. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  31. package/lib/types/components/HistorySearchDialog.js +2 -2
  32. package/lib/types/components/LangPicker.d.ts +14 -0
  33. package/lib/types/components/LangPicker.d.ts.map +1 -0
  34. package/lib/types/components/LangPicker.js +17 -0
  35. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  36. package/lib/types/components/LoadedContextPanel.js +3 -1
  37. package/lib/types/components/Markdown.d.ts.map +1 -1
  38. package/lib/types/components/Markdown.js +12 -3
  39. package/lib/types/components/MessageList.d.ts +43 -2
  40. package/lib/types/components/MessageList.d.ts.map +1 -1
  41. package/lib/types/components/MessageList.js +553 -41
  42. package/lib/types/components/ModelPicker.d.ts +4 -1
  43. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  44. package/lib/types/components/ModelPicker.js +2 -2
  45. package/lib/types/components/PermissionsPicker.d.ts +21 -0
  46. package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
  47. package/lib/types/components/PermissionsPicker.js +27 -0
  48. package/lib/types/components/PlanPicker.d.ts +15 -0
  49. package/lib/types/components/PlanPicker.d.ts.map +1 -0
  50. package/lib/types/components/PlanPicker.js +18 -0
  51. package/lib/types/components/PresetPicker.d.ts +4 -1
  52. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  53. package/lib/types/components/PresetPicker.js +2 -2
  54. package/lib/types/components/PromptInput.d.ts +4 -3
  55. package/lib/types/components/PromptInput.d.ts.map +1 -1
  56. package/lib/types/components/PromptInput.js +248 -29
  57. package/lib/types/components/RewindPicker.d.ts +12 -1
  58. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  59. package/lib/types/components/RewindPicker.js +6 -4
  60. package/lib/types/components/ScrollbarGutter.d.ts +28 -0
  61. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
  62. package/lib/types/components/ScrollbarGutter.js +68 -0
  63. package/lib/types/components/Select.d.ts +8 -1
  64. package/lib/types/components/Select.d.ts.map +1 -1
  65. package/lib/types/components/Select.js +4 -2
  66. package/lib/types/components/SkillsPicker.d.ts +4 -1
  67. package/lib/types/components/SkillsPicker.d.ts.map +1 -1
  68. package/lib/types/components/SkillsPicker.js +2 -2
  69. package/lib/types/components/SubagentCard.d.ts +2 -1
  70. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  71. package/lib/types/components/SubagentCard.js +6 -1
  72. package/lib/types/components/SubagentDashboard.d.ts +4 -0
  73. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  74. package/lib/types/components/SubagentDashboard.js +9 -1
  75. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  76. package/lib/types/components/SubagentDetailScene.js +5 -4
  77. package/lib/types/components/SuggestionCard.d.ts +63 -0
  78. package/lib/types/components/SuggestionCard.d.ts.map +1 -0
  79. package/lib/types/components/SuggestionCard.js +77 -0
  80. package/lib/types/components/ThemePicker.d.ts +4 -1
  81. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  82. package/lib/types/components/ThemePicker.js +2 -2
  83. package/lib/types/components/ThinkingToggle.d.ts +4 -1
  84. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  85. package/lib/types/components/ThinkingToggle.js +2 -2
  86. package/lib/types/components/TimelineRail.d.ts +53 -0
  87. package/lib/types/components/TimelineRail.d.ts.map +1 -0
  88. package/lib/types/components/TimelineRail.js +190 -0
  89. package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
  90. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
  91. package/lib/types/components/WorkspaceFlowPicker.js +4 -2
  92. package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
  93. package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
  94. package/lib/types/components/WorkspaceMenuPicker.js +19 -0
  95. package/lib/types/components/WorkspacePicker.d.ts +4 -1
  96. package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
  97. package/lib/types/components/WorkspacePicker.js +2 -2
  98. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  99. package/lib/types/components/approvals/ApprovalPanel.js +5 -1
  100. package/lib/types/components/design-system/ListItem.d.ts +8 -1
  101. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  102. package/lib/types/components/design-system/ListItem.js +8 -3
  103. package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
  104. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  105. package/lib/types/components/messages/AssistantTextMessage.js +6 -2
  106. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  107. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  108. package/lib/types/components/messages/AssistantThinkingMessage.js +10 -4
  109. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
  110. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  111. package/lib/types/components/messages/AssistantToolUseMessage.js +4 -2
  112. package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
  113. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  114. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  115. package/lib/types/components/questions/AskUserQuestionPanel.js +34 -2
  116. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  117. package/lib/types/components/questions/PlanReviewPanel.js +13 -2
  118. package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
  119. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  120. package/lib/types/components/sessions/SessionListRow.js +4 -2
  121. package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
  122. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
  123. package/lib/types/components/trajectory/HotspotView.js +8 -2
  124. package/lib/types/components/trajectory/Ledger.d.ts +9 -1
  125. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
  126. package/lib/types/components/trajectory/Ledger.js +23 -5
  127. package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
  128. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
  129. package/lib/types/components/trajectory/WaveBand.js +7 -2
  130. package/lib/types/dsh-adapter/channel.d.ts +16 -5
  131. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/channel.js +332 -29
  133. package/lib/types/dsh-adapter/index.d.ts +10 -2
  134. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  135. package/lib/types/dsh-adapter/index.js +4 -1
  136. package/lib/types/dsh-adapter/plugin.d.ts +0 -9
  137. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/plugin.js +136 -6
  139. package/lib/types/i18n.d.ts +176 -15
  140. package/lib/types/i18n.d.ts.map +1 -1
  141. package/lib/types/i18n.js +51 -8
  142. package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
  143. package/lib/types/ink/components/AlternateScreen.js +13 -1
  144. package/lib/types/ink/components/App.d.ts +12 -1
  145. package/lib/types/ink/components/App.d.ts.map +1 -1
  146. package/lib/types/ink/components/App.js +101 -4
  147. package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
  148. package/lib/types/ink/components/ClockContext.js +2 -0
  149. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  150. package/lib/types/ink/components/ScrollBox.js +170 -91
  151. package/lib/types/ink/constants.d.ts +9 -0
  152. package/lib/types/ink/constants.d.ts.map +1 -1
  153. package/lib/types/ink/constants.js +9 -0
  154. package/lib/types/ink/events/click-event.d.ts +7 -16
  155. package/lib/types/ink/events/click-event.d.ts.map +1 -1
  156. package/lib/types/ink/events/click-event.js +16 -19
  157. package/lib/types/ink/events/event-handlers.d.ts +11 -1
  158. package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
  159. package/lib/types/ink/events/event-handlers.js +2 -0
  160. package/lib/types/ink/events/input-event.d.ts +9 -0
  161. package/lib/types/ink/events/input-event.d.ts.map +1 -1
  162. package/lib/types/ink/events/input-event.js +4 -0
  163. package/lib/types/ink/events/pointer-event.d.ts +61 -0
  164. package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
  165. package/lib/types/ink/events/pointer-event.js +61 -0
  166. package/lib/types/ink/events/wheel-event.d.ts +17 -0
  167. package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
  168. package/lib/types/ink/events/wheel-event.js +20 -0
  169. package/lib/types/ink/geometry-trace.d.ts +51 -0
  170. package/lib/types/ink/geometry-trace.d.ts.map +1 -0
  171. package/lib/types/ink/geometry-trace.js +83 -0
  172. package/lib/types/ink/hit-test.d.ts +56 -1
  173. package/lib/types/ink/hit-test.d.ts.map +1 -1
  174. package/lib/types/ink/hit-test.js +146 -8
  175. package/lib/types/ink/ink.d.ts +58 -1
  176. package/lib/types/ink/ink.d.ts.map +1 -1
  177. package/lib/types/ink/ink.js +230 -29
  178. package/lib/types/ink/node-cache.d.ts +5 -0
  179. package/lib/types/ink/node-cache.d.ts.map +1 -1
  180. package/lib/types/ink/parse-keypress.d.ts +8 -0
  181. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  182. package/lib/types/ink/parse-keypress.js +101 -12
  183. package/lib/types/ink/render-node-to-output.d.ts +10 -0
  184. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  185. package/lib/types/ink/render-node-to-output.js +111 -18
  186. package/lib/types/ink/timeline-rail.d.ts +138 -0
  187. package/lib/types/ink/timeline-rail.d.ts.map +1 -0
  188. package/lib/types/ink/timeline-rail.js +179 -0
  189. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  190. package/lib/types/ink/wrap-text.js +47 -5
  191. package/lib/types/screens/Chat.d.ts.map +1 -1
  192. package/lib/types/screens/Chat.js +819 -337
  193. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  194. package/lib/types/screens/SessionBrowser.js +56 -29
  195. package/lib/types/screens/Settings.d.ts.map +1 -1
  196. package/lib/types/screens/Settings.js +64 -22
  197. package/lib/types/screens/StatusLine.d.ts +2 -1
  198. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  199. package/lib/types/screens/StatusLine.js +17 -1
  200. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
  201. package/lib/types/screens/TrajectoryScene.js +81 -14
  202. package/lib/types/screens/chatOverlay.d.ts +221 -0
  203. package/lib/types/screens/chatOverlay.d.ts.map +1 -0
  204. package/lib/types/screens/chatOverlay.js +114 -0
  205. package/lib/types/tips.d.ts.map +1 -1
  206. package/lib/types/tips.js +42 -6
  207. package/lib/types/tuiDisplayPrefs.d.ts +15 -0
  208. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  209. package/lib/types/tuiDisplayPrefs.js +9 -0
  210. package/lib/types/utils/debug.d.ts +10 -0
  211. package/lib/types/utils/debug.d.ts.map +1 -1
  212. package/lib/types/utils/debug.js +24 -0
  213. package/lib/types/utils/paths.d.ts.map +1 -1
  214. package/lib/types/utils/paths.js +1 -0
  215. package/package.json +4 -2
@@ -9,7 +9,7 @@
9
9
  import type { Context } from '@deepseek-ai/cordis';
10
10
  import Schema from '@deepseek-ai/schemastery';
11
11
  import type { SessionModeSpec } from '../sessionModes.js';
12
- import { type StatusBarConfig, type ToolBackground } from '../tuiDisplayPrefs.js';
12
+ import { type ScrollGutterMode, type StatusBarConfig, type ToolBackground } from '../tuiDisplayPrefs.js';
13
13
  export declare const name = "dsh-tui";
14
14
  export declare const inject: string[];
15
15
  /**
@@ -53,7 +53,11 @@ export interface Config {
53
53
  * `ctx used/window` readout) in the status footer; off hides that row
54
54
  * while the status/mode lines stay (issue #29). */
55
55
  contextBar?: boolean;
56
- /** Run in the terminal's alternate screen (Claude Code fullscreen layout). */
56
+ /** Run in the terminal's alternate screen (Claude Code fullscreen layout).
57
+ * Defaults to true — the fullscreen surface is the more complete one
58
+ * (mouse, timeline rail, scrollbar gutter, selection copy), so fresh
59
+ * installs start there; cordis.yml `fullscreen: false` or a /settings
60
+ * toggle opts back into the inline main-screen layout. */
57
61
  fullscreen?: boolean;
58
62
  /** UI language: `en` / `zh`. When absent, the `DSH_TUI_LANG` env var wins,
59
63
  * then the `/lang` choice persisted in `~/.dsh-tui/lang.json`, then `zh`. */
@@ -73,6 +77,10 @@ export interface Config {
73
77
  thinkingFold?: 'preview' | 'full';
74
78
  /** Tool-card background strength; defaults to no added background. */
75
79
  toolBackground?: ToolBackground;
80
+ /** What the fullscreen transcript's right gutter shows (settings
81
+ * `dsh-tui.scrollGutter`): `timeline` turn rail (default), `scrollbar`
82
+ * proportional thumb, or `hidden`. */
83
+ scrollGutter?: ScrollGutterMode;
76
84
  /** Status-footer field visibility and compact presentation preferences. */
77
85
  statusBar?: Partial<StatusBarConfig>;
78
86
  /** Shift+Tab session-mode cycle (array order IS the cycle order; index 0
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAsB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAErG,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,sEAAsE;IACtE,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACpC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CA8ChC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAsB,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE5H,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;+DAI2D;IAC3D,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,sEAAsE;IACtE,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B;;2CAEuC;IACvC,YAAY,CAAC,EAAE,gBAAgB,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACpC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CAiDhC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASvE"}
@@ -25,12 +25,13 @@ export const Config = Schema.object({
25
25
  activity: Schema.boolean().default(true),
26
26
  activityFrames: Schema.string().required(false),
27
27
  contextBar: Schema.boolean().default(true),
28
- fullscreen: Schema.boolean().default(false),
28
+ fullscreen: Schema.boolean().default(true),
29
29
  lang: Schema.string().required(false),
30
30
  preset: Schema.string().required(false),
31
31
  diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
32
32
  thinkingFold: Schema.union(['preview', 'full']).default('preview'),
33
33
  toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
34
+ scrollGutter: Schema.union(['timeline', 'scrollbar', 'hidden']).default('timeline'),
34
35
  statusBar: Schema.object({
35
36
  compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
36
37
  model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
@@ -42,6 +43,8 @@ export const Config = Schema.object({
42
43
  tps: Schema.boolean().default(DEFAULT_STATUS_BAR.tps),
43
44
  gitBranch: Schema.boolean().default(DEFAULT_STATUS_BAR.gitBranch),
44
45
  sessionTitle: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionTitle),
46
+ sessionId: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionId),
47
+ goal: Schema.boolean().default(DEFAULT_STATUS_BAR.goal),
45
48
  mode: Schema.boolean().default(DEFAULT_STATUS_BAR.mode),
46
49
  contextBar: Schema.boolean().default(DEFAULT_STATUS_BAR.contextBar),
47
50
  activity: Schema.boolean().default(DEFAULT_STATUS_BAR.activity),
@@ -1,15 +1,6 @@
1
1
  import type { Agent } from '@deepseek-ai/dsh-agent';
2
2
  import type { Context } from '@deepseek-ai/cordis';
3
3
  import { Config } from './index.js';
4
- /**
5
- * Claude Code style interactive TUI front door for DeepSeek Harness agents.
6
- *
7
- * The plugin attaches to (or creates) one agent, renders a chat transcript
8
- * from the agent's session log and live `session/event` records, and submits
9
- * user turns through `Agent.followup`. It is a client-driver front door like
10
- * `dsh-jsonrpc`: the surrounding `cordis.yml` supplies the agent spine, the
11
- * LLM adapter, and the tool plugins.
12
- */
13
4
  export declare function apply(ctx: Context, config: Config): Promise<void>;
14
5
  /**
15
6
  * Distinguish a user-driven exit from a cordis context teardown (issue #12).
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAqCnC;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA60BvE;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AA6DnC,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAm8BvE;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV"}
@@ -23,9 +23,10 @@ import { clearResumeTarget, writeResumeTarget } from '../sessionHistory.js';
23
23
  import { resolveSessionCwd } from '../utils/workspaceRoot.js';
24
24
  import { checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isVersionNewer, resolveDshProfileName, resolveTuiUpdateTarget, updateTuiAndRestart } from '../update.js';
25
25
  import { getLang, isLang, resolveStartupLang, setLang, t, writeLangPref } from '../i18n.js';
26
- import { DEFAULT_STATUS_BAR, normalizeStatusBar, normalizeToolBackground } from '../tuiDisplayPrefs.js';
26
+ import { DEFAULT_STATUS_BAR, normalizeScrollGutter, normalizeStatusBar, normalizeToolBackground } from '../tuiDisplayPrefs.js';
27
27
  import { detectLegacyEnv, migrateLegacyDataDir, RENAMED_ENV } from '../utils/paths.js';
28
28
  import { attachHerdrIntegration } from '../herdr.js';
29
+ import { logMouseDebug } from '../utils/debug.js';
29
30
  import { Chat } from '../screens/Chat.js';
30
31
  import { getHostDialogStore } from './dialogs.js';
31
32
  import { getHostStatusStore } from './status.js';
@@ -48,6 +49,19 @@ import { CLEAR_ITERM2_PROGRESS, CLEAR_TAB_STATUS, supportsTabStatus, wrapForMult
48
49
  * `dsh-jsonrpc`: the surrounding `cordis.yml` supplies the agent spine, the
49
50
  * LLM adapter, and the tool plugins.
50
51
  */
52
+ /**
53
+ * Fullscreen decision latched across host recomposes. The launcher disposes
54
+ * and re-mounts the plugin tree (teardown → apply() runs again) — a fresh
55
+ * apply() re-resolves `bootedFullscreen` from cordis config, and the
56
+ * settings user layer (settings.yaml) can arrive after the 300ms
57
+ * `settingsReady` bound when the recompose is also re-mounting the settings
58
+ * service. The tree would then mount INLINE and `fullscreenFrozen` would
59
+ * swallow the late application — the app lands on the main screen
60
+ * ("exited fullscreen", dead mouse, unpinned input) until restart. A
61
+ * session that already mounted fullscreen must never regress on a
62
+ * recompose: latch the decision.
63
+ */
64
+ let lastBootedFullscreen;
51
65
  export async function apply(ctx, config) {
52
66
  if (!process.stdout.isTTY) {
53
67
  throw new Error('dsh-tui requires an interactive terminal (stdout must be a TTY).');
@@ -329,9 +343,31 @@ export async function apply(ctx, config) {
329
343
  diffLayout: config.diffLayout,
330
344
  thinkingFold: config.thinkingFold,
331
345
  toolBackground: config.toolBackground,
346
+ scrollGutter: config.scrollGutter,
332
347
  statusBar: config.statusBar,
333
348
  handle,
334
349
  });
350
+ // Fullscreen layout decision: the settings user layer (edited through the
351
+ // /settings screen) overrides cordis.yml when set. The settings injection
352
+ // below resolves it synchronously when the host settings service is up —
353
+ // i.e. before the tree mounts. `fullscreenFrozen` latches at mount: the
354
+ // exit funnel and the AlternateScreen wrap must keep reading the mode this
355
+ // session ACTUALLY runs, never a mid-session edit meant for the next boot
356
+ // (swapping layouts requires re-mounting the whole tree).
357
+ let bootedFullscreen = config.fullscreen === true;
358
+ let fullscreenFrozen = false;
359
+ // The settings service may come up AFTER this plugin's apply: the cordis
360
+ // inject callback defers until the service registers, so the first
361
+ // `apply(scope.get())` below can land after the mount (field report: the
362
+ // /settings fullscreen toggle never took effect — the frozen latch below
363
+ // swallowed the late callback and bootedFullscreen stayed false). The
364
+ // mount must therefore WAIT for the first settings application (bounded —
365
+ // a bare embedder without a settings service must not deadlock).
366
+ let resolveSettingsReady;
367
+ const settingsReady = new Promise(resolve => {
368
+ resolveSettingsReady = () => resolve();
369
+ setTimeout(resolve, 300);
370
+ });
335
371
  // Register the dsh-tui settings namespace so the /settings screen can
336
372
  // edit it (the section below was '命名空间未注册' without this): the
337
373
  // user layer in settings.yaml wins over cordis.yml's diffLayout, and
@@ -341,6 +377,7 @@ export async function apply(ctx, config) {
341
377
  diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
342
378
  thinkingFold: Schema.union(['preview', 'full']).default('preview'),
343
379
  toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
380
+ scrollGutter: Schema.union(['timeline', 'scrollbar', 'hidden']).default('timeline'),
344
381
  statusBar: Schema.object({
345
382
  compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
346
383
  model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
@@ -352,6 +389,8 @@ export async function apply(ctx, config) {
352
389
  tps: Schema.boolean().default(DEFAULT_STATUS_BAR.tps),
353
390
  gitBranch: Schema.boolean().default(DEFAULT_STATUS_BAR.gitBranch),
354
391
  sessionTitle: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionTitle),
392
+ sessionId: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionId),
393
+ goal: Schema.boolean().default(DEFAULT_STATUS_BAR.goal),
355
394
  mode: Schema.boolean().default(DEFAULT_STATUS_BAR.mode),
356
395
  contextBar: Schema.boolean().default(DEFAULT_STATUS_BAR.contextBar),
357
396
  activity: Schema.boolean().default(DEFAULT_STATUS_BAR.activity),
@@ -367,6 +406,9 @@ export async function apply(ctx, config) {
367
406
  // the effective language (see the section's format below) and lets
368
407
  // cordis.yml / lang.json keep their precedence.
369
408
  lang: Schema.union(['zh', 'en']),
409
+ // Same no-default rule: unset keeps cordis.yml's `fullscreen`
410
+ // decisive; set overrides it from the next boot on.
411
+ fullscreen: Schema.boolean(),
370
412
  }));
371
413
  const applyLayout = (value) => {
372
414
  channel.setDiffLayout(value.diffLayout ?? config.diffLayout ?? 'auto');
@@ -377,6 +419,15 @@ export async function apply(ctx, config) {
377
419
  const applyMinimal = (value) => {
378
420
  channel.setMinimal(value.minimal ?? false);
379
421
  };
422
+ // Fullscreen: only meaningful before the tree mounts (the freeze latch
423
+ // above). A later doc change (mid-session /settings edit) is persisted
424
+ // by the service and picked up on the next boot; the watch below says
425
+ // so with a notify.
426
+ const applyFullscreen = (value) => {
427
+ if (!fullscreenFrozen && typeof value.fullscreen === 'boolean') {
428
+ bootedFullscreen = value.fullscreen;
429
+ }
430
+ };
380
431
  // The /settings language field writes `lang` through the settings
381
432
  // service (user layer): apply it live and mirror it to lang.json so
382
433
  // the /lang command and next-boot resolution agree. DSH_TUI_LANG
@@ -393,6 +444,7 @@ export async function apply(ctx, config) {
393
444
  const applyDisplay = (value) => {
394
445
  channel.setThinkingFold(value.thinkingFold ?? config.thinkingFold ?? 'preview');
395
446
  channel.setToolBackground(normalizeToolBackground(value.toolBackground ?? config.toolBackground));
447
+ channel.setScrollGutter(normalizeScrollGutter(value.scrollGutter ?? config.scrollGutter));
396
448
  channel.setStatusBar(normalizeStatusBar(value.statusBar ?? config.statusBar));
397
449
  };
398
450
  const apply = (next) => {
@@ -401,11 +453,16 @@ export async function apply(ctx, config) {
401
453
  applyMinimal(next);
402
454
  applyLang(next);
403
455
  applyDisplay(next);
456
+ applyFullscreen(next);
404
457
  };
405
458
  apply(scope.get());
406
459
  scope.watch(next => {
407
460
  apply(next);
461
+ if (typeof next.fullscreen === 'boolean' && next.fullscreen !== bootedFullscreen) {
462
+ channel.notify(t('settings-fullscreen-restart'), { color: 'warning' });
463
+ }
408
464
  });
465
+ resolveSettingsReady?.();
409
466
  });
410
467
  // The /settings screen's own section: the dsh-tui namespace comes from
411
468
  // the settings registration above, and the declared selects write `lang`
@@ -436,6 +493,22 @@ export async function apply(ctx, config) {
436
493
  return value === undefined || value === null ? getLang() : String(value);
437
494
  },
438
495
  },
496
+ {
497
+ path: ['fullscreen'],
498
+ label: 'Fullscreen mode',
499
+ descriptions: { zh: '全屏模式' },
500
+ // 故意不用 "alt-screen" 这类终端术语:读者要的是行为差异。鼠标
501
+ // 两种模式都可用(整屏页面自带鼠标跟踪),别让描述暗示关掉就
502
+ // 没有鼠标——最常见的误解。长度对齐既有最长 hint(单行假设)。
503
+ hint: 'On: app takes the whole screen (vim/less style), in-app mouse. Off: native scrollback; full-page screens keep the mouse. Restart to apply.',
504
+ hintDescriptions: { zh: '开启:接管整个终端(同 vim/less),应用内鼠标;关闭:终端原生滚动选择;整屏页两种模式都有鼠标。重启生效。' },
505
+ kind: 'boolean',
506
+ format(value) {
507
+ // Unset in settings.yaml: show what THIS session booted with
508
+ // (the cordis.yml resolution) instead of a misleading false.
509
+ return value === undefined || value === null ? String(bootedFullscreen) : String(value);
510
+ },
511
+ },
439
512
  {
440
513
  path: ['diffLayout'],
441
514
  label: 'Diff layout',
@@ -474,6 +547,19 @@ export async function apply(ctx, config) {
474
547
  { value: 'strong', label: 'Strong', descriptions: { zh: '明显' } },
475
548
  ],
476
549
  },
550
+ {
551
+ path: ['scrollGutter'],
552
+ label: 'Transcript gutter',
553
+ descriptions: { zh: '转录边栏' },
554
+ hint: 'Right gutter of the fullscreen transcript: per-turn timeline ticks, a proportional scrollbar, or nothing.',
555
+ hintDescriptions: { zh: '全屏转录区右侧边栏:按轮次的时间线节点、比例滚动条,或留空。' },
556
+ kind: 'select',
557
+ options: [
558
+ { value: 'timeline', label: 'Turn timeline', descriptions: { zh: '轮次时间线' } },
559
+ { value: 'scrollbar', label: 'Scrollbar', descriptions: { zh: '滚动条' } },
560
+ { value: 'hidden', label: 'Hidden', descriptions: { zh: '隐藏' } },
561
+ ],
562
+ },
477
563
  {
478
564
  path: ['statusBar', 'compact'],
479
565
  label: 'Compact status bar',
@@ -564,6 +650,24 @@ export async function apply(ctx, config) {
564
650
  group: 'status-bar',
565
651
  kind: 'boolean',
566
652
  },
653
+ {
654
+ path: ['statusBar', 'sessionId'],
655
+ label: 'Show session id',
656
+ descriptions: { zh: '显示会话 ID' },
657
+ hint: 'Show the short session id (# + first 8 chars) — it matches the session log filename for --resume.',
658
+ hintDescriptions: { zh: '显示短会话 ID(# + 前 8 位)——与日志文件名对应,方便 --resume 定位。' },
659
+ group: 'status-bar',
660
+ kind: 'boolean',
661
+ },
662
+ {
663
+ path: ['statusBar', 'goal'],
664
+ label: 'Show goal status',
665
+ descriptions: { zh: '显示 Goal 状态' },
666
+ hint: 'Show a compact goal chip (phase glyph + rounds) in the status footer while a goal exists.',
667
+ hintDescriptions: { zh: '存在 Goal 时,在底部状态栏显示紧凑的 Goal 状态(阶段符号与轮次)。' },
668
+ group: 'status-bar',
669
+ kind: 'boolean',
670
+ },
567
671
  {
568
672
  path: ['statusBar', 'mode'],
569
673
  label: 'Show session mode',
@@ -695,7 +799,7 @@ export async function apply(ctx, config) {
695
799
  if (error !== undefined) {
696
800
  const message = error instanceof Error ? error.message : String(error);
697
801
  ctx.logger.error(`dsh-tui: exit after error: ${message}`);
698
- void finishExit(ctx, instance, config.fullscreen === true, undefined, `dsh-tui crashed: ${message}`, () => disposeRootAndExit(ctx, 1));
802
+ void finishExit(ctx, instance, bootedFullscreen, undefined, `dsh-tui crashed: ${message}`, () => disposeRootAndExit(ctx, 1));
699
803
  return;
700
804
  }
701
805
  if (updateRequested) {
@@ -705,7 +809,7 @@ export async function apply(ctx, config) {
705
809
  catch {
706
810
  // Resume persistence is best effort and must never block an update.
707
811
  }
708
- void finishExit(ctx, instance, config.fullscreen === true, 'Updating @deepseek-harness-tui/dsh-tui and restarting…', undefined, () => runUpdate(ctx, profile, channel.agentId, updateTargetVersion));
812
+ void finishExit(ctx, instance, bootedFullscreen, 'Updating @deepseek-harness-tui/dsh-tui and restarting…', undefined, () => runUpdate(ctx, profile, channel.agentId, updateTargetVersion));
709
813
  return;
710
814
  }
711
815
  // Judge against the live session behind the channel (channel.agentId),
@@ -729,10 +833,19 @@ export async function apply(ctx, config) {
729
833
  const hint = resumable
730
834
  ? `Resume with the command below:\n${resumeCommand(profile, channel.agentId)}`
731
835
  : undefined;
732
- void finishExit(ctx, instance, config.fullscreen === true, hint, undefined, () => disposeRootAndExit(ctx, 0));
836
+ void finishExit(ctx, instance, bootedFullscreen, hint, undefined, () => disposeRootAndExit(ctx, 0));
733
837
  },
734
838
  });
735
839
  const handleExit = funnel.handleExit;
840
+ // Chat's `fullscreen` prop must match the root wrap below, or the
841
+ // full-screen surfaces inside Chat (session browser, settings, trajectory,
842
+ // subagent pages) would nest a SECOND <AlternateScreen> — whose unmount
843
+ // writes DEC 1049 exit and drops the whole app back to the main screen
844
+ // (the stable /resume→Esc "exited fullscreen" repro). The prop is captured
845
+ // when the element is created, so wait for the settings first-application
846
+ // BEFORE creating Chat: the element must see the same bootedFullscreen the
847
+ // root tree resolves after settingsReady below.
848
+ await settingsReady;
736
849
  const chat = React.createElement(Chat, {
737
850
  channel,
738
851
  questionStore,
@@ -746,7 +859,7 @@ export async function apply(ctx, config) {
746
859
  // Full-screen surfaces inside Chat — the trajectory scene and the session
747
860
  // browser — enter the alt screen themselves in inline mode; in fullscreen
748
861
  // the tree is already wrapped below, so they must not nest.
749
- fullscreen: config.fullscreen === true,
862
+ fullscreen: bootedFullscreen,
750
863
  onExit: () => handleExit(),
751
864
  // Only a `dsh --profile <name>` launch has a profile installation for
752
865
  // `/update` to act on; source checkouts and `--config` overlays get the
@@ -791,12 +904,28 @@ export async function apply(ctx, config) {
791
904
  });
792
905
  },
793
906
  });
907
+ // Freeze the fullscreen decision only NOW, right before the tree mounts:
908
+ // Chat above was created after the same settingsReady await, so the root
909
+ // wrap and the `fullscreen` prop share one value; a mid-session /settings
910
+ // edit from here on is persisted for the next boot (the watch notifies),
911
+ // never applied live (swapping layouts requires re-mounting the tree).
912
+ // Host recompose hardening: never regress a fullscreen session to inline
913
+ // on a re-mount whose settings application arrived late (see the module
914
+ // latch note). A fresh process still resolves from config + settings
915
+ // normally — the latch is undefined there.
916
+ if (bootedFullscreen === false && lastBootedFullscreen === true) {
917
+ bootedFullscreen = true;
918
+ }
919
+ fullscreenFrozen = true;
794
920
  // fullscreen: wrap the tree in <AlternateScreen> (DEC 1049 + SGR mouse
795
921
  // tracking), which turns on in-app text selection (copy-on-select via
796
922
  // useCopyOnSelect), wheel scroll, and click/hover hit-testing. Inline
797
923
  // mode leaves the mouse to the terminal emulator's native selection.
798
- const tree = React.createElement(ThemeProvider, null, config.fullscreen ? React.createElement(AlternateScreen, null, chat) : chat);
924
+ const tree = React.createElement(ThemeProvider, null, bootedFullscreen ? React.createElement(AlternateScreen, null, chat) : chat);
799
925
  instance = await render(tree, { exitOnCtrlC: false });
926
+ const isRecompose = lastBootedFullscreen !== undefined;
927
+ lastBootedFullscreen = bootedFullscreen;
928
+ logMouseDebug('apply mount', { bootedFullscreen, isRecompose });
800
929
  // Check in the background so registry latency never delays the first frame.
801
930
  // A failed/offline check is intentionally silent; the manual `/update`
802
931
  // command remains available regardless of network access.
@@ -814,6 +943,7 @@ export async function apply(ctx, config) {
814
943
  // skill commands (issue #86) would survive this exact recompose and the
815
944
  // re-mounted channel would find the names taken, freezing its menu.
816
945
  ctx.effect(() => () => {
946
+ logMouseDebug('apply teardown');
817
947
  funnel.markTeardown();
818
948
  channel.releaseContributions();
819
949
  instance?.unmount();
@@ -363,6 +363,14 @@ declare const dict: {
363
363
  readonly zh: "模型已切换,但工作区挂载失败 · {{err}}";
364
364
  readonly en: "Model switched, but workspace attachment failed · {{err}}";
365
365
  };
366
+ readonly 'model-usage': {
367
+ readonly zh: "用法:/model <provider/model>(如 deepseek/deepseek-v4-flash)";
368
+ readonly en: "Usage: /model <provider/model> (e.g. deepseek/deepseek-v4-flash)";
369
+ };
370
+ readonly 'model-unknown': {
371
+ readonly zh: "未知模型「{{spec}}」· /model 查看全部";
372
+ readonly en: "Unknown model \"{{spec}}\" · /model to view all";
373
+ };
366
374
  readonly 'compact-unavailable': {
367
375
  readonly zh: "压缩不可用——当前 leaf 没有压缩服务";
368
376
  readonly en: "Compaction unavailable · no compaction service in this leaf";
@@ -643,6 +651,22 @@ declare const dict: {
643
651
  readonly zh: "用法:/workspace resume | rename <名称> | open <路径或 URI>{{commands}}";
644
652
  readonly en: "Usage: /workspace resume | rename <name> | open <path-or-URI>{{commands}}";
645
653
  };
654
+ readonly 'workspace-menu-title': {
655
+ readonly zh: "Workspace 操作";
656
+ readonly en: "Workspace actions";
657
+ };
658
+ readonly 'workspace-menu-resume-desc': {
659
+ readonly zh: "切换到另一个工作区";
660
+ readonly en: "Switch to another workspace";
661
+ };
662
+ readonly 'workspace-menu-rename-desc': {
663
+ readonly zh: "重命名当前工作区(需输入名称)";
664
+ readonly en: "Rename the current workspace (needs a name)";
665
+ };
666
+ readonly 'workspace-menu-open-desc': {
667
+ readonly zh: "打开路径或工作区 URI(需输入路径)";
668
+ readonly en: "Open a path or workspace URI (needs a path)";
669
+ };
646
670
  readonly 'workspace-open-usage': {
647
671
  readonly zh: "用法:/workspace open <路径或 URI>";
648
672
  readonly en: "Usage: /workspace open <path-or-URI>";
@@ -775,26 +799,74 @@ declare const dict: {
775
799
  readonly zh: "使用 /provider 管理 DSH 凭据;若来源为 env,请删除对应环境变量并重启 dsh-tui";
776
800
  readonly en: "Manage DSH credentials with /provider; for env sources, remove the corresponding environment variable and restart dsh-tui";
777
801
  };
778
- readonly 'permissions-policy-hint': {
802
+ readonly 'permission-policy-hint': {
779
803
  readonly zh: "DSH 权限策略由 fs-policy / bash-sandbox 配置决定(当前 leaf:workspace 内读写、写入需已读文件)。";
780
804
  readonly en: "DSH permission policy is set by fs-policy / bash-sandbox config (current leaf: read/write in workspace, writes need a prior read).";
781
805
  };
782
- readonly 'permissions-approval-hint': {
806
+ readonly 'permission-approval-hint': {
783
807
  readonly zh: "审批通道已挂载:命令申请权限提升(sandbox_permissions)时弹出审批条,Yes 放行一次、No / Esc 拒绝。";
784
808
  readonly en: "The approval channel is mounted: sandbox escalations (sandbox_permissions) raise an approval bar — Yes allows once, No / Esc rejects.";
785
809
  };
786
- readonly 'permissions-preset-hint': {
787
- readonly zh: "/permission 可查看与切换权限预设(read-only / workspace-write / danger-full-access)。";
788
- readonly en: "/permission shows and switches permission presets (read-only / workspace-write / danger-full-access).";
789
- };
790
- readonly 'permissions-root-hint': {
810
+ readonly 'permission-root-hint': {
791
811
  readonly zh: "当前文件系统策略以工作目录为根:{{cwd}}";
792
812
  readonly en: "Current filesystem policy is rooted at the working directory: {{cwd}}";
793
813
  };
794
- readonly 'permissions-path-hint': {
814
+ readonly 'permission-path-hint': {
795
815
  readonly zh: "模型工具相对路径均解析自该目录;跨目录访问由 fs-policy 拦截。";
796
816
  readonly en: "Relative paths of model tools resolve from this directory; cross-directory access is blocked by fs-policy.";
797
817
  };
818
+ readonly 'permission-current': {
819
+ readonly zh: "当前预设 {{name}}";
820
+ readonly en: "Current preset {{name}}";
821
+ };
822
+ readonly 'permission-picker-title': {
823
+ readonly zh: "权限预设";
824
+ readonly en: "Permission preset";
825
+ };
826
+ readonly 'permission-preset-readonly': {
827
+ readonly zh: "只读";
828
+ readonly en: "Read-only";
829
+ };
830
+ readonly 'permission-preset-readonly-desc': {
831
+ readonly zh: "会话只读:不写文件、不执行命令";
832
+ readonly en: "Read-only session: no file writes, no commands";
833
+ };
834
+ readonly 'permission-preset-workspace-write': {
835
+ readonly zh: "工作区读写";
836
+ readonly en: "Workspace read/write";
837
+ };
838
+ readonly 'permission-preset-workspace-write-desc': {
839
+ readonly zh: "工作区内读写;写入需先读该文件";
840
+ readonly en: "Read/write inside the workspace; writes need a prior read";
841
+ };
842
+ readonly 'permission-preset-full-access': {
843
+ readonly zh: "完全访问";
844
+ readonly en: "Full access";
845
+ };
846
+ readonly 'permission-preset-full-access-desc': {
847
+ readonly zh: "不受限读写,无需审批";
848
+ readonly en: "Unrestricted access, no approvals";
849
+ };
850
+ readonly 'plan-picker-title': {
851
+ readonly zh: "计划模式";
852
+ readonly en: "Plan mode";
853
+ };
854
+ readonly 'plan-mode-on': {
855
+ readonly zh: "开启";
856
+ readonly en: "On";
857
+ };
858
+ readonly 'plan-mode-on-desc': {
859
+ readonly zh: "进入计划模式:只读,先规划后动手";
860
+ readonly en: "Enter plan mode: read-only, plan before acting";
861
+ };
862
+ readonly 'plan-mode-off': {
863
+ readonly zh: "关闭";
864
+ readonly en: "Off";
865
+ };
866
+ readonly 'plan-mode-off-desc': {
867
+ readonly zh: "退出计划模式,恢复正常执行";
868
+ readonly en: "Exit plan mode, back to normal execution";
869
+ };
798
870
  readonly 'hooks-not-mounted': {
799
871
  readonly zh: "DSH hooks(dsh-hooks-claude / dsh-hooks-codex)未在本 leaf 挂载。";
800
872
  readonly en: "DSH hooks (dsh-hooks-claude / dsh-hooks-codex) are not mounted in this leaf.";
@@ -1159,6 +1231,66 @@ declare const dict: {
1159
1231
  readonly zh: "摆尾巴3";
1160
1232
  readonly en: "tail3";
1161
1233
  };
1234
+ readonly 'sugg-commands-title': {
1235
+ readonly zh: "命令";
1236
+ readonly en: "commands";
1237
+ };
1238
+ readonly 'sugg-files-title': {
1239
+ readonly zh: "文件";
1240
+ readonly en: "files";
1241
+ };
1242
+ readonly 'sugg-count': {
1243
+ readonly zh: "共 {{n}} 项";
1244
+ readonly en: "{{n}} items";
1245
+ };
1246
+ readonly 'sugg-more-above': {
1247
+ readonly zh: "↑{{n}}";
1248
+ readonly en: "↑{{n}}";
1249
+ };
1250
+ readonly 'sugg-more-below': {
1251
+ readonly zh: "↓{{n}}";
1252
+ readonly en: "↓{{n}}";
1253
+ };
1254
+ readonly 'sugg-status-desc': {
1255
+ readonly zh: "显示当前选择";
1256
+ readonly en: "Show the current choice";
1257
+ };
1258
+ readonly 'sugg-lang-zh-desc': {
1259
+ readonly zh: "切换界面语言到中文";
1260
+ readonly en: "Switch the UI language to Chinese";
1261
+ };
1262
+ readonly 'sugg-lang-en-desc': {
1263
+ readonly zh: "切换界面语言到英文";
1264
+ readonly en: "Switch the UI language to English";
1265
+ };
1266
+ readonly 'sugg-theme-auto-desc': {
1267
+ readonly zh: "跟随终端背景自动切换";
1268
+ readonly en: "Follow the terminal background";
1269
+ };
1270
+ readonly 'sugg-theme-builtin-desc': {
1271
+ readonly zh: "内置主题";
1272
+ readonly en: "Built-in theme";
1273
+ };
1274
+ readonly 'sugg-theme-user-desc': {
1275
+ readonly zh: "用户主题({{base}} 基底)";
1276
+ readonly en: "User theme ({{base}} base)";
1277
+ };
1278
+ readonly 'sugg-effort-level-desc': {
1279
+ readonly zh: "思考强度档位";
1280
+ readonly en: "Reasoning effort level";
1281
+ };
1282
+ readonly 'sugg-activity-frames-desc': {
1283
+ readonly zh: "列出或切换动画帧预设";
1284
+ readonly en: "List or switch frame presets";
1285
+ };
1286
+ readonly 'sugg-activity-frame-desc': {
1287
+ readonly zh: "动画帧预设";
1288
+ readonly en: "Animation frame preset";
1289
+ };
1290
+ readonly 'settings-fullscreen-restart': {
1291
+ readonly zh: "全屏设置已保存,重启 dsh-tui 后生效";
1292
+ readonly en: "Fullscreen preference saved — restart dsh-tui to apply";
1293
+ };
1162
1294
  readonly 'help-for-commands': {
1163
1295
  readonly zh: "/ 查看命令";
1164
1296
  readonly en: "/ for commands";
@@ -1219,6 +1351,14 @@ declare const dict: {
1219
1351
  readonly zh: "ctrl+g 打开编辑器";
1220
1352
  readonly en: "ctrl+g to open editor";
1221
1353
  };
1354
+ readonly 'help-fold-todos': {
1355
+ readonly zh: "{{mod}}q 折叠待办";
1356
+ readonly en: "{{mod}}q to fold todos";
1357
+ };
1358
+ readonly 'goal-todo-fold-hint': {
1359
+ readonly zh: "{{mod}}q 折叠";
1360
+ readonly en: "{{mod}}q to fold";
1361
+ };
1222
1362
  readonly 'help-commands-title': {
1223
1363
  readonly zh: "命令:";
1224
1364
  readonly en: "commands:";
@@ -1567,6 +1707,14 @@ declare const dict: {
1567
1707
  readonly zh: "技能列表加载失败";
1568
1708
  readonly en: "Failed to load the skill list";
1569
1709
  };
1710
+ readonly 'skills-unknown': {
1711
+ readonly zh: "未知技能「{{name}}」";
1712
+ readonly en: "Unknown skill \"{{name}}\"";
1713
+ };
1714
+ readonly 'skills-not-invocable': {
1715
+ readonly zh: "技能「{{name}}」不可直接调用";
1716
+ readonly en: "Skill \"{{name}}\" is not directly invocable";
1717
+ };
1570
1718
  readonly 'plugin-scene-crashed': {
1571
1719
  readonly zh: "插件场景「{{id}}」渲染崩溃:{{err}}(已自动关闭)";
1572
1720
  readonly en: "Plugin scene \"{{id}}\" crashed while rendering: {{err}} (closed)";
@@ -1864,12 +2012,16 @@ declare const dict: {
1864
2012
  readonly en: "Summary folded";
1865
2013
  };
1866
2014
  readonly 'new-message': {
1867
- readonly zh: "{{n}} 条新消息";
1868
- readonly en: "1 new message";
2015
+ readonly zh: "↓ {{n}} 条新消息";
2016
+ readonly en: "↓ 1 new message";
1869
2017
  };
1870
2018
  readonly 'new-messages': {
1871
- readonly zh: "{{n}} 条新消息";
1872
- readonly en: "{{n}} new messages";
2019
+ readonly zh: "↓ {{n}} 条新消息";
2020
+ readonly en: "↓ {{n}} new messages";
2021
+ };
2022
+ readonly 'back-to-bottom': {
2023
+ readonly zh: "↓ 回到底部(Enter/End)";
2024
+ readonly en: "↓ back to bottom (Enter/End)";
1873
2025
  };
1874
2026
  readonly 'theme-builtin-base': {
1875
2027
  readonly zh: "内置 · {{name}} 基底";
@@ -2384,9 +2536,6 @@ declare const dict: {
2384
2536
  readonly 'cmd-desc-logout': {
2385
2537
  readonly zh: "清除 API 凭证";
2386
2538
  };
2387
- readonly 'cmd-desc-permissions': {
2388
- readonly zh: "查看权限策略状态";
2389
- };
2390
2539
  readonly 'cmd-desc-add-dir': {
2391
2540
  readonly zh: "查看文件系统策略范围";
2392
2541
  };
@@ -2489,6 +2638,18 @@ declare const dict: {
2489
2638
  readonly zh: "语言「{{lang}}」切换失败(无法写入 ~/.dsh-tui/lang.json)";
2490
2639
  readonly en: "Language \"{{lang}}\" switch failed (cannot write ~/.dsh-tui/lang.json)";
2491
2640
  };
2641
+ readonly 'lang-picker-title': {
2642
+ readonly zh: "界面语言";
2643
+ readonly en: "UI language";
2644
+ };
2645
+ readonly 'lang-zh-desc': {
2646
+ readonly zh: "简体中文(默认)";
2647
+ readonly en: "Simplified Chinese (default)";
2648
+ };
2649
+ readonly 'lang-en-desc': {
2650
+ readonly zh: "English(英文)";
2651
+ readonly en: "English";
2652
+ };
2492
2653
  readonly 'status-cache-label': {
2493
2654
  readonly zh: "缓存 ";
2494
2655
  readonly en: "cache ";