@deepseek-harness-tui/dsh-tui 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/README.md +69 -256
  2. package/bin/dsh-tui.js +172 -5
  3. package/cordis.patch.yml +16 -4
  4. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
  5. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
  6. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
  7. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
  8. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
  9. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
  10. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
  11. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
  12. package/dsh-ecosystem-spec/registry/README.md +14 -14
  13. package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
  14. package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
  15. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
  16. package/lib/types/cc/hyperlink.d.ts +7 -1
  17. package/lib/types/cc/hyperlink.d.ts.map +1 -1
  18. package/lib/types/cc/hyperlink.js +3 -2
  19. package/lib/types/cc/markdown.d.ts.map +1 -1
  20. package/lib/types/cc/markdown.js +33 -3
  21. package/lib/types/cc/sessionColors.d.ts +27 -0
  22. package/lib/types/cc/sessionColors.d.ts.map +1 -0
  23. package/lib/types/cc/sessionColors.js +39 -0
  24. package/lib/types/commands.d.ts.map +1 -1
  25. package/lib/types/commands.js +6 -0
  26. package/lib/types/components/AutoRecapRow.d.ts +23 -0
  27. package/lib/types/components/AutoRecapRow.d.ts.map +1 -0
  28. package/lib/types/components/AutoRecapRow.js +23 -0
  29. package/lib/types/components/ColorPicker.d.ts +17 -0
  30. package/lib/types/components/ColorPicker.d.ts.map +1 -0
  31. package/lib/types/components/ColorPicker.js +20 -0
  32. package/lib/types/components/CommandSuggestions.d.ts +3 -1
  33. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  34. package/lib/types/components/ContextBarView.d.ts +33 -0
  35. package/lib/types/components/ContextBarView.d.ts.map +1 -0
  36. package/lib/types/components/ContextBarView.js +46 -0
  37. package/lib/types/components/EffortInputBorder.d.ts +12 -1
  38. package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
  39. package/lib/types/components/EffortInputBorder.js +22 -5
  40. package/lib/types/components/FileActionsPanel.d.ts +22 -0
  41. package/lib/types/components/FileActionsPanel.d.ts.map +1 -0
  42. package/lib/types/components/FileActionsPanel.js +28 -0
  43. package/lib/types/components/FileSuggestions.d.ts +3 -1
  44. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  45. package/lib/types/components/MessageList.d.ts +3 -1
  46. package/lib/types/components/MessageList.d.ts.map +1 -1
  47. package/lib/types/components/MessageList.js +13 -6
  48. package/lib/types/components/ModelPicker.d.ts +26 -4
  49. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  50. package/lib/types/components/ModelPicker.js +26 -6
  51. package/lib/types/components/PromptInput.d.ts.map +1 -1
  52. package/lib/types/components/PromptInput.js +365 -57
  53. package/lib/types/components/RecapPanel.d.ts +25 -0
  54. package/lib/types/components/RecapPanel.d.ts.map +1 -0
  55. package/lib/types/components/RecapPanel.js +55 -0
  56. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  57. package/lib/types/components/ScrollbarGutter.js +55 -4
  58. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  59. package/lib/types/components/SubagentCard.js +6 -4
  60. package/lib/types/components/SuggestionCard.d.ts +4 -2
  61. package/lib/types/components/SuggestionCard.d.ts.map +1 -1
  62. package/lib/types/components/TimelineRail.d.ts.map +1 -1
  63. package/lib/types/components/TimelineRail.js +9 -2
  64. package/lib/types/components/design-system/ThemeProvider.d.ts +7 -0
  65. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  66. package/lib/types/components/design-system/ThemeProvider.js +2 -1
  67. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
  68. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  69. package/lib/types/components/messages/AssistantToolUseMessage.js +36 -8
  70. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +7 -3
  71. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  72. package/lib/types/components/questions/AskUserQuestionPanel.js +41 -9
  73. package/lib/types/dsh-adapter/channel.d.ts +101 -2
  74. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  75. package/lib/types/dsh-adapter/channel.js +969 -93
  76. package/lib/types/dsh-adapter/compat/index.d.ts +8 -6
  77. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  78. package/lib/types/dsh-adapter/compat/index.js +8 -6
  79. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +150 -0
  80. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  81. package/lib/types/dsh-adapter/compat/sessionLog.js +518 -41
  82. package/lib/types/dsh-adapter/contract.d.ts +1 -1
  83. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  84. package/lib/types/dsh-adapter/contract.js +1 -0
  85. package/lib/types/dsh-adapter/extension-events.d.ts +1 -1
  86. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  87. package/lib/types/dsh-adapter/index.d.ts +10 -0
  88. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  89. package/lib/types/dsh-adapter/index.js +5 -0
  90. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/plugin.js +317 -8
  92. package/lib/types/dsh-adapter/presets.d.ts +18 -0
  93. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  94. package/lib/types/dsh-adapter/presets.js +31 -0
  95. package/lib/types/dsh-adapter/providerWizard.d.ts +29 -1
  96. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  97. package/lib/types/dsh-adapter/providerWizard.js +89 -5
  98. package/lib/types/dsh-adapter/questions.d.ts +19 -2
  99. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  100. package/lib/types/dsh-adapter/questions.js +53 -10
  101. package/lib/types/dsh-adapter/recap.d.ts +49 -0
  102. package/lib/types/dsh-adapter/recap.d.ts.map +1 -0
  103. package/lib/types/dsh-adapter/recap.js +121 -0
  104. package/lib/types/dsh-adapter/sessionTree.d.ts +314 -0
  105. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -0
  106. package/lib/types/dsh-adapter/sessionTree.js +954 -0
  107. package/lib/types/dsh-adapter/shortcuts.d.ts +15 -44
  108. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  109. package/lib/types/dsh-adapter/shortcuts.js +28 -165
  110. package/lib/types/dsh-adapter/types.d.ts +1 -1
  111. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  112. package/lib/types/herdr.js +1 -1
  113. package/lib/types/i18n.d.ts +604 -176
  114. package/lib/types/i18n.d.ts.map +1 -1
  115. package/lib/types/i18n.js +206 -72
  116. package/lib/types/ink/log-update.d.ts.map +1 -1
  117. package/lib/types/ink/log-update.js +21 -0
  118. package/lib/types/migrationPrefs.d.ts +60 -0
  119. package/lib/types/migrationPrefs.d.ts.map +1 -0
  120. package/lib/types/migrationPrefs.js +97 -0
  121. package/lib/types/modelGroups.d.ts +72 -0
  122. package/lib/types/modelGroups.d.ts.map +1 -0
  123. package/lib/types/modelGroups.js +97 -0
  124. package/lib/types/modelRecents.d.ts +39 -0
  125. package/lib/types/modelRecents.d.ts.map +1 -0
  126. package/lib/types/modelRecents.js +97 -0
  127. package/lib/types/native-ts/yoga-layout/index.d.ts +11 -0
  128. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  129. package/lib/types/native-ts/yoga-layout/index.js +31 -1
  130. package/lib/types/oauth.d.ts +15 -0
  131. package/lib/types/oauth.d.ts.map +1 -0
  132. package/lib/types/oauth.js +14 -0
  133. package/lib/types/plugin-spec/registry.d.ts +1 -1
  134. package/lib/types/plugin-spec/registry.js +1 -1
  135. package/lib/types/reload.d.ts +109 -0
  136. package/lib/types/reload.d.ts.map +1 -0
  137. package/lib/types/reload.js +118 -0
  138. package/lib/types/screens/Chat.d.ts +3 -1
  139. package/lib/types/screens/Chat.d.ts.map +1 -1
  140. package/lib/types/screens/Chat.js +588 -64
  141. package/lib/types/screens/SessionTree.d.ts +27 -0
  142. package/lib/types/screens/SessionTree.d.ts.map +1 -0
  143. package/lib/types/screens/SessionTree.js +555 -0
  144. package/lib/types/screens/StatusLine.d.ts +0 -9
  145. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  146. package/lib/types/screens/StatusLine.js +215 -52
  147. package/lib/types/screens/StatusMetrics.d.ts +35 -3
  148. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  149. package/lib/types/screens/StatusMetrics.js +63 -8
  150. package/lib/types/screens/chatOverlay.d.ts +17 -1
  151. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  152. package/lib/types/screens/chatOverlay.js +3 -1
  153. package/lib/types/tips.d.ts.map +1 -1
  154. package/lib/types/tips.js +22 -4
  155. package/lib/types/update.d.ts +159 -0
  156. package/lib/types/update.d.ts.map +1 -1
  157. package/lib/types/update.js +496 -30
  158. package/lib/types/utils/debug.d.ts +1 -1
  159. package/lib/types/utils/debug.js +3 -3
  160. package/lib/types/utils/fileTarget.d.ts +46 -0
  161. package/lib/types/utils/fileTarget.d.ts.map +1 -0
  162. package/lib/types/utils/fileTarget.js +178 -0
  163. package/lib/types/utils/keymap.d.ts +134 -0
  164. package/lib/types/utils/keymap.d.ts.map +1 -0
  165. package/lib/types/utils/keymap.js +311 -0
  166. package/lib/types/utils/mentions.d.ts +25 -2
  167. package/lib/types/utils/mentions.d.ts.map +1 -1
  168. package/lib/types/utils/mentions.js +69 -10
  169. package/lib/types/utils/openExternal.d.ts +50 -0
  170. package/lib/types/utils/openExternal.d.ts.map +1 -0
  171. package/lib/types/utils/openExternal.js +170 -0
  172. package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -0
  173. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +140 -0
  174. package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +11 -0
  175. package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -0
  176. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.d.ts +14 -0
  177. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.js +67 -0
  178. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +64 -0
  179. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.js +170 -0
  180. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +79 -0
  181. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +196 -0
  182. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +68 -0
  183. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +193 -0
  184. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.d.ts +32 -0
  185. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.js +101 -0
  186. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +31 -0
  187. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +68 -0
  188. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.d.ts +69 -0
  189. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.js +129 -0
  190. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +70 -0
  191. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
  192. package/node_modules/@dsh-std/command/LICENSE +21 -21
  193. package/node_modules/@dsh-std/command/README.md +26 -26
  194. package/node_modules/@dsh-std/command/README.zh.md +28 -28
  195. package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
  196. package/node_modules/@dsh-std/command/package.json +22 -22
  197. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  198. package/node_modules/@dsh-std/connection/LICENSE +21 -21
  199. package/node_modules/@dsh-std/connection/README.md +42 -42
  200. package/node_modules/@dsh-std/connection/README.zh.md +42 -42
  201. package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  202. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  203. package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  204. package/node_modules/@dsh-std/connection/package.json +20 -20
  205. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  206. package/node_modules/@dsh-std/core/LICENSE +21 -21
  207. package/node_modules/@dsh-std/core/README.md +13 -13
  208. package/node_modules/@dsh-std/core/README.zh.md +13 -13
  209. package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  210. package/node_modules/@dsh-std/core/package.json +21 -21
  211. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  212. package/node_modules/@dsh-std/manifest/LICENSE +21 -21
  213. package/node_modules/@dsh-std/manifest/README.md +5 -5
  214. package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  215. package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  216. package/node_modules/@dsh-std/manifest/package.json +20 -20
  217. package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  218. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
  219. package/node_modules/@dsh-std/messages/LICENSE +21 -21
  220. package/node_modules/@dsh-std/messages/README.md +5 -5
  221. package/node_modules/@dsh-std/messages/README.zh.md +7 -7
  222. package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
  223. package/node_modules/@dsh-std/messages/package.json +20 -20
  224. package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
  225. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  226. package/node_modules/@dsh-std/presentation/LICENSE +21 -21
  227. package/node_modules/@dsh-std/presentation/README.md +27 -27
  228. package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  229. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  230. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  231. package/node_modules/@dsh-std/presentation/package.json +25 -25
  232. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
  233. package/node_modules/@dsh-std/storage/LICENSE +21 -21
  234. package/node_modules/@dsh-std/storage/README.md +5 -5
  235. package/node_modules/@dsh-std/storage/README.zh.md +7 -7
  236. package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
  237. package/node_modules/@dsh-std/storage/package.json +20 -20
  238. package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
  239. package/package.json +17 -5
  240. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  241. package/presets/liangshen/instruction-hint.mjs +8 -0
  242. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  243. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
  244. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
  245. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
  246. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  247. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  248. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  249. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
  250. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  251. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
  252. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
  253. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
  254. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  255. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
  256. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  257. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
  258. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
  259. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  260. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  261. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
  262. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  263. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  264. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
  265. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
  266. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  267. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  268. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  269. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
  270. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  271. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
  272. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
  273. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
  274. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  275. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
  276. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  277. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
  278. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
  279. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
  280. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  281. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
  282. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  283. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
  284. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
  285. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
  286. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  287. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
  288. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  289. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
  290. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
  291. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
  292. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  293. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  294. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  295. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
  296. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  297. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
  298. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
  299. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
  300. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  301. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
  302. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  303. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
  304. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
  305. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
  306. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  307. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA01BA,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,IAAI,CAAA;AACvC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAUxD,uEAAuE;AACvE,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAG1B,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAG5D;AAED,qCAAqC;AACrC,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAED,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAGxC;AAED,iDAAiD;AACjD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAM/D;AAED;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAMlF;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAS5D;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAkB,GAAG,IAAI,GAAG,SAAS,CAMtE;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAQ1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAavC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAI9B,+DAA+D;AAC/D,eAAO,MAAM,KAAK,uBAAwB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAm8B0D,CAAA;AAEpE,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,IAAI,CAAA;AACvC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAUxD,uEAAuE;AACvE,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAG1B,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAG5D;AAED,qCAAqC;AACrC,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAED,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAGxC;AAED,iDAAiD;AACjD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAG/D;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAGlF;AAED,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAQ,CAAA;AAI1G;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAS5D;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAkB,GAAG,IAAI,GAAG,SAAS,CAMtE;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAQ1E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAWvC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}
package/lib/types/i18n.js CHANGED
@@ -11,9 +11,18 @@
11
11
  * 5. `zh` (the original hard-coded language)
12
12
  *
13
13
  * `/lang` switches at runtime and hot-swaps the whole UI. The dictionary is
14
- * a flat key → per-language string map; `t(key, params)` substitutes
15
- * `{{name}}` placeholders with the given params. Missing keys render the
16
- * key itself so a typo is visible in the UI instead of silently blank.
14
+ * a flat key → per-language text map; `t(key, params)` substitutes
15
+ * `{{name}}` placeholders with the given params. A per-language value is
16
+ * either a plain template or `{ one, other }` plural forms selected via
17
+ * `Intl.PluralRules` on the `count` param (zh has no grammatical number and
18
+ * always resolves to `other`). Missing keys render the key itself so a typo
19
+ * is visible in the UI instead of silently blank.
20
+ *
21
+ * The dictionary shape is enforced at compile time (`satisfies` below):
22
+ * every entry carries zh, and en is optional only for the `cmd-desc-*`
23
+ * family whose en truth lives in the command registry (see {@link tOr}).
24
+ * scripts/verify-i18n.ts adds the checks types cannot express: placeholder
25
+ * parity between languages, single-brace typos, and dead keys.
17
26
  */
18
27
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
19
28
  import { join } from 'node:path';
@@ -50,7 +59,7 @@ const dict = {
50
59
  'export-model': { zh: '- 模型: {{model}}', en: '- Model: {{model}}' },
51
60
  'export-session': { zh: '- 会话: {{id}}', en: '- Session: {{id}}' },
52
61
  'export-dir': { zh: '- 目录: {{cwd}}', en: '- Directory: {{cwd}}' },
53
- 'mentions-attached': { zh: '已附加 {{count}} 个文件引用', en: 'Attached {{count}} file reference(s)' },
62
+ 'mentions-attached': { zh: '已附加 {{count}} 个文件引用', en: { one: 'Attached {{count}} file reference', other: 'Attached {{count}} file references' } },
54
63
  'mentions-missing': { zh: '未找到引用: {{paths}}', en: 'References not found: {{paths}}' },
55
64
  'send-failed': { zh: '发送失败 · {{err}}', en: 'Send failed · {{err}}' },
56
65
  'export-user-section': { zh: '## 用户', en: '## User' },
@@ -85,7 +94,6 @@ const dict = {
85
94
  'subagent-archived': { zh: ' 已归档', en: ' archived' },
86
95
  'subagent-query-failed': { zh: '查询失败 · {{err}}', en: 'Query failed · {{err}}' },
87
96
  'subagent-tools': { zh: '工具', en: 'Tools' },
88
- 'subagent-expand-hint': { zh: '按 Enter 展开完整输出', en: 'Press Enter to expand full output' },
89
97
  'subagent-status-running': { zh: '运行中', en: 'running' },
90
98
  'subagent-status-completed': { zh: '已完成', en: 'completed' },
91
99
  'subagent-status-failed': { zh: '失败', en: 'failed' },
@@ -96,6 +104,70 @@ const dict = {
96
104
  'rewind-fork-failed': { zh: '无法回退到该处 · {{err}}', en: 'Cannot rewind to this point · {{err}}' },
97
105
  'rewind-create-failed': { zh: '回退失败——无法创建替代会话', en: 'Rewind failed — could not create the replacement session' },
98
106
  'rewind-attach-failed': { zh: '已回退,但工作区挂载失败 · {{err}}', en: 'Session rewound, but workspace attachment failed · {{err}}' },
107
+ 'rewind-no-persistence': { zh: '回退不可用——持久化服务未加载', en: 'Rewind unavailable — session persistence not loaded' },
108
+ 'rewind-load-failed': { zh: '无法读取该会话日志 · {{err}}', en: 'Could not read that session log · {{err}}' },
109
+ 'rewind-first-message': { zh: '不能回退到第一条消息之前', en: 'Cannot rewind past the very first message' },
110
+ 'rewind-noop': { zh: '该点之后没有可回退的内容', en: 'Nothing to rewind past this point' },
111
+ 'rewind-session-changed': { zh: '会话已切换,回退已放弃', en: 'The session changed; the rewind was dropped' },
112
+ 'tree-unavailable': { zh: '会话树不可用——持久化服务未加载', en: 'Session tree unavailable — session persistence not loaded' },
113
+ 'fork-unavailable': { zh: '分叉不可用——会话服务未加载', en: 'Fork unavailable — session services not loaded' },
114
+ 'fork-while-working': { zh: '回合运行中,无法分叉会话', en: 'Cannot fork while a turn is running' },
115
+ 'fork-failed': { zh: '分叉失败 · {{err}}', en: 'Fork failed · {{err}}' },
116
+ 'fork-create-failed': { zh: '分叉失败——无法创建分叉会话', en: 'Fork failed — could not create the forked session' },
117
+ 'fork-attach-failed': { zh: '已分叉,但工作区挂载失败 · {{err}}', en: 'Session forked, but workspace attachment failed · {{err}}' },
118
+ 'fork-done': {
119
+ zh: '已分叉({{id}})——仍在原会话中\n新进程进入分叉:{{command}}',
120
+ en: 'Forked ({{id}}) — still in the original session\nEnter the fork in a new process: {{command}}',
121
+ },
122
+ // ── /tree screen (session family tree) ─────────────────────────────────
123
+ 'tree-title': { zh: '会话树', en: 'Session tree' },
124
+ 'tree-sessions': { zh: '会话', en: 'sessions' },
125
+ 'tree-loading': { zh: '正在加载会话树…', en: 'Loading the session tree…' },
126
+ 'tree-rewinding': { zh: '正在分叉并切换…', en: 'Forking and switching…' },
127
+ 'tree-empty': { zh: '没有可显示的条目', en: 'No entries to show' },
128
+ 'tree-truncated': { zh: '已截断', en: 'truncated' },
129
+ 'tree-search': { zh: '输入即搜索…', en: 'Type to search…' },
130
+ 'tree-filter-default': { zh: '默认', en: 'default' },
131
+ 'tree-filter-no-tools': { zh: '无工具', en: 'no tools' },
132
+ 'tree-filter-user-only': { zh: '仅用户', en: 'user only' },
133
+ 'tree-filter-all': { zh: '全部', en: 'all' },
134
+ 'tree-kind-user': { zh: '用户消息', en: 'user message' },
135
+ 'tree-kind-assistant': { zh: '助手回复', en: 'assistant message' },
136
+ 'tree-kind-tool': { zh: '工具调用', en: 'tool call' },
137
+ 'tree-kind-compact': { zh: '压缩检查点', en: 'compaction' },
138
+ 'tree-kind-interrupt': { zh: '中断', en: 'interrupt' },
139
+ 'tree-kind-notice': { zh: '通知', en: 'notice' },
140
+ 'tree-empty-fork': { zh: '(空分叉)', en: '(empty fork)' },
141
+ 'tree-unreadable': { zh: '(日志无法读取)', en: '(unreadable log)' },
142
+ 'tree-unloaded': { zh: '(超出预算未加载)', en: '(not loaded — over budget)' },
143
+ 'tree-first-message': { zh: '不能回退到第一条消息之前', en: 'Cannot rewind past the very first message' },
144
+ 'tree-adopt-live': { zh: '当前会话就在这条分支上', en: 'The live session is already on this branch' },
145
+ 'tree-adopt-unavailable': { zh: '该分支无法整体切换(未加载到末端)', en: 'Cannot adopt this branch (its tip was not loaded)' },
146
+ 'tree-menu-rewind': { zh: '回退到这里', en: 'Rewind here' },
147
+ 'tree-menu-rewind-detail': { zh: '丢弃该轮对话,提示词回到输入框', en: 'Drops that turn; its prompt returns to the input' },
148
+ 'tree-menu-fork': { zh: '从这分叉', en: 'Fork here' },
149
+ 'tree-menu-fork-detail': { zh: '保留这条消息,从这里开新分支', en: 'Keeps this entry and branches here' },
150
+ 'tree-menu-adopt': { zh: '切换到该分支', en: 'Adopt this branch' },
151
+ 'tree-menu-adopt-detail': { zh: '保留整条分支并切换过去', en: 'Switches to the whole branch, content kept' },
152
+ 'tree-menu-cancel': { zh: '取消', en: 'Cancel' },
153
+ 'tree-confirm-rewind': { zh: '回退到「{{text}}」?', en: 'Rewind to "{{text}}"?' },
154
+ 'tree-confirm-drop': { zh: '回退到「{{text}}」?该轮 {{n}} 条消息将丢弃', en: 'Rewind to "{{text}}"? Drops that turn ({{n}} entries)' },
155
+ 'tree-confirm-adopt': { zh: '切换到「{{text}}」所在分支?', en: 'Switch to the branch of "{{text}}"?' },
156
+ 'tree-confirm-drops-branch': { zh: '注意:该分支的全部内容都在这一轮里,回退后将看不到它们', en: 'Heads-up: this branch\u2019s whole content is that one turn — it disappears from the fork' },
157
+ 'tree-hint': {
158
+ zh: '**Enter** 菜单 · **{{mod}}F** 从这分叉 · **{{mod}}B** 切到分支 · **{{mod}}O** 过滤 · 点击行出菜单 · 输入搜索 · Esc 退出',
159
+ en: '**Enter** menu · **{{mod}}F** fork here · **{{mod}}B** adopt branch · **{{mod}}O** filter · click a row for the menu · type to search · Esc exits',
160
+ },
161
+ 'tree-hint-short': { zh: '**Enter** 菜单 · 点击行出菜单 · Esc 退出', en: '**Enter** menu · click a row · Esc exits' },
162
+ 'tree-hint-menu': { zh: '**↑↓** 选择 · **Enter** 执行 · 首字母直达 · Esc 返回', en: '**↑↓** move · **Enter** run · letter keys jump · Esc back' },
163
+ 'tree-hint-confirm': { zh: '**Enter** 确认 · Esc 取消', en: '**Enter** to confirm · Esc to cancel' },
164
+ 'tree-refused': { zh: '操作未执行(原因已记录到会话通知)', en: 'Not executed — the reason was notified to the conversation' },
165
+ 'tree-rewind-failed': { zh: '操作失败 · {{message}}', en: 'Action failed · {{message}}' },
166
+ 'tree-rewound': { zh: '已回退——编辑后重新发送', en: 'Rewound — edit and resend' },
167
+ 'tree-forked': { zh: '已从此处分叉', en: 'Forked from this point' },
168
+ 'tree-adopted': { zh: '已切换到该分支', en: 'Switched to that branch' },
169
+ 'tree-preview-title': { zh: '预览', en: 'Preview' },
170
+ 'tree-branch-live': { zh: '当前会话', en: 'live session' },
99
171
  'resume-while-working': { zh: '回合运行中,无法恢复会话', en: 'Cannot resume while a turn is running' },
100
172
  'resume-unavailable': { zh: '恢复不可用——agents 服务未加载', en: 'Resume unavailable — agents service not loaded' },
101
173
  'resume-failed': { zh: '恢复失败 · {{err}}', en: 'Resume failed · {{err}}' },
@@ -120,8 +192,6 @@ const dict = {
120
192
  'turn-failed': { zh: '回合出错{{detail}}', en: 'Turn error{{detail}}' },
121
193
  // ── questions.ts ─────────────────────────────────────────────────────
122
194
  'questionnaire-answered': { zh: '📋 问卷已答 · {{total}} 题', en: '📋 Questionnaire answered · {{total}} questions' },
123
- // ── customTheme.ts (doc example only) ───────────────────────────────
124
- 'theme-sakura-name': { zh: '樱花粉', en: 'Sakura Pink' },
125
195
  // ── utils/loaded-context.ts ─────────────────────────────────────────
126
196
  'context-truncated': { zh: '…(已截断)', en: '… (truncated)' },
127
197
  'context-sections': { zh: '系统提示词 {{n}} 段', en: 'System prompt {{n}} sections' },
@@ -142,7 +212,6 @@ const dict = {
142
212
  'context-panel-expand': { zh: '展开', en: 'Expand' },
143
213
  'context-panel-collapse': { zh: '折叠', en: 'Collapse' },
144
214
  'copied-chars': { zh: '已复制 {{n}} 个字符', en: 'Copied {{n}} characters' },
145
- 'activity-usage-name': { zh: '/activity frames <名>', en: '/activity frames <name>' },
146
215
  'activity-current-preset': { zh: '当前预设 {{name}}', en: 'Current preset {{name}}' },
147
216
  'activity-switch-hint': { zh: '切换 /activity(选择器)或 /activity frames <名>', en: 'Switch /activity (picker) or /activity frames <name>' },
148
217
  'activity-persist-hint': { zh: '持久化 ~/.dsh-tui/working-activity.json(重启后仍生效)', en: 'Persisted ~/.dsh-tui/working-activity.json (survives restart)' },
@@ -156,7 +225,6 @@ const dict = {
156
225
  '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)' },
157
226
  'preset-lock-hint': { zh: '锁定规则 已开始的会话不可切换(官方 blank-only 规则)', en: 'Lock rule started sessions cannot switch (official blank-only rule)' },
158
227
  'preset-roster-unmounted': { zh: '当前组合未挂载 agent-presets 名册(preset 不可用)', en: 'The agent-presets roster is not mounted (presets unavailable)' },
159
- 'theme-name-arg': { zh: '/theme <名字>', en: '/theme <name>' },
160
228
  'theme-current': { zh: '当前主题 {{name}}', en: 'Current theme {{name}}' },
161
229
  'theme-switch-hint': { zh: '切换 /theme(选择器)或 /theme <名字>', en: 'Switch /theme (picker) or /theme <name>' },
162
230
  'theme-persist-hint': { zh: '持久化 ~/.dsh-tui/theme.json(重启后仍生效;DSH_TUI_THEME 优先)', en: 'Persisted ~/.dsh-tui/theme.json (survives restart; DSH_TUI_THEME wins)' },
@@ -177,14 +245,13 @@ const dict = {
177
245
  'workspace-uri-invalid': { zh: '无法解析工作区目标:{{uri}}', en: 'Cannot resolve workspace target: {{uri}}' },
178
246
  'workspace-uri-failed': { zh: '加载工作区失败 · {{err}}', en: 'Failed to load workspace · {{err}}' },
179
247
  'workspace-switch-working': { zh: 'Agent 运行中,无法切换工作区', en: 'Cannot switch workspaces while the agent is running' },
180
- 'workspace-open-invalid': { zh: '无法打开工作区:{target} 不是存在的目录', en: 'Cannot open workspace: {target} is not an existing directory' },
248
+ 'workspace-open-invalid': { zh: '无法打开工作区:{{target}} 不是存在的目录', en: 'Cannot open workspace: {{target}} is not an existing directory' },
181
249
  'workspace-switched': { zh: '已切换工作区:{{target}}', en: 'Workspace switched: {{target}}' },
182
250
  'workspace-flow-hint': { zh: '**Enter** 选择 · Esc 退出', en: '**Enter** select · Esc to exit' },
183
251
  'workspace-flow-edit-hint': { zh: '**Enter** 选择当前目录 · Tab 手动输入路径 · Esc 退出', en: '**Enter** select current directory · Tab enter a path · Esc to exit' },
184
252
  'workspace-flow-input-hint': { zh: '输入绝对路径 · **Enter** 读取目录 · Esc 返回', en: 'Enter an absolute path · **Enter** load directory · Esc back' },
185
253
  'workspace-flow-input-empty': { zh: '目录路径不能为空', en: 'Directory path cannot be empty' },
186
254
  'workspace-flow-loading': { zh: '正在连接并读取目录… · Esc 关闭', en: 'Connecting and loading directories… · Esc to close' },
187
- 'workspace-command-usage': { zh: '用法:/workspace resume | rename <名称> | open <路径或 URI>{{commands}}', en: 'Usage: /workspace resume | rename <name> | open <path-or-URI>{{commands}}' },
188
255
  'workspace-menu-title': { zh: 'Workspace 操作', en: 'Workspace actions' },
189
256
  'workspace-menu-resume-desc': { zh: '切换到另一个工作区', en: 'Switch to another workspace' },
190
257
  'workspace-menu-rename-desc': { zh: '重命名当前工作区(需输入名称)', en: 'Rename the current workspace (needs a name)' },
@@ -222,6 +289,13 @@ const dict = {
222
289
  'login-base-url': { zh: 'Base URL: {{url}}', en: 'Base URL: {{url}}' },
223
290
  'login-official-endpoint': { zh: '官方端点', en: 'official endpoint' },
224
291
  'login-logout-hint': { zh: '使用 /provider 管理 DSH 凭据;若来源为 env,请删除对应环境变量并重启 dsh-tui', en: 'Manage DSH credentials with /provider; for env sources, remove the corresponding environment variable and restart dsh-tui' },
292
+ // /login 的 OAuth 账号状态段(dsh-auth 类插件挂载时追加)
293
+ 'login-oauth-heading': { zh: '订阅账号(OAuth):', en: 'Subscriptions (OAuth):' },
294
+ 'login-oauth-row': { zh: ' {{provider}} — {{state}}', en: ' {{provider}} — {{state}}' },
295
+ 'login-oauth-in': { zh: '已登录 · 令牌到期 {{time}}', en: 'signed in · token expires {{time}}' },
296
+ 'login-oauth-expired': { zh: '已登录但令牌已过期,重新登录可恢复', en: 'signed in but the token expired — sign in again to restore' },
297
+ 'login-oauth-signed-out': { zh: '未登录', en: 'not signed in' },
298
+ 'login-oauth-hint': { zh: ' 登录/登出:/provider 订阅账号登录,或 /auth login <provider>', en: ' Sign in/out: /provider subscription sign-in, or /auth login <provider>' },
225
299
  'permission-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).' },
226
300
  'permission-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.' },
227
301
  'permission-root-hint': { zh: '当前文件系统策略以工作目录为根:{{cwd}}', en: 'Current filesystem policy is rooted at the working directory: {{cwd}}' },
@@ -249,10 +323,26 @@ const dict = {
249
323
  'update-check-failed': { zh: '无法确认新版本(网络或 registry 不可达),已尝试直接更新……', en: 'Could not confirm a newer version (network or registry unreachable); attempting the update anyway…' },
250
324
  'update-refused-deadlock': { zh: '已取消更新:镜像 registry 目前只能装到 v{{latest}},而该版本在旧全局启动器的 patch 下会启动死锁(#183/#307);官方最新为 v{{authoritative}},待镜像同步后再 /update。', en: 'Update cancelled: the mirror registry can only serve v{{latest}}, which deadlocks boot under older global-launcher patches (#183/#307); official latest is v{{authoritative}} — retry /update after the mirror syncs.' },
251
325
  'update-mirror-lag': { zh: '镜像 registry 滞后:本次安装 v{{latest}};官方最新 v{{authoritative}},镜像同步后可再 /update。', en: 'Mirror registry lag: installing v{{latest}} now; official latest is v{{authoritative}} — run /update again once the mirror syncs.' },
326
+ // ── /reload (pi-style soft reload) ────────────────────────────────────
327
+ 'reload-header': { zh: '已重读偏好文件:', en: 'Preferences reloaded:' },
328
+ 'reload-applied': { zh: '{{kind}} {{from}} → {{to}}(已应用)', en: '{{kind}} {{from}} → {{to}} (applied)' },
329
+ 'reload-unchanged': { zh: '{{kind}} 无变化', en: '{{kind}} unchanged' },
330
+ 'reload-skipped-env': { zh: '{{kind}} 跳过:环境变量优先', en: '{{kind}} skipped: env override wins' },
331
+ 'reload-skipped-config': { zh: '{{kind}} 跳过:显式配置优先', en: '{{kind}} skipped: explicit config wins' },
332
+ 'reload-skipped-invalid': { zh: '{{kind}} 跳过:文件缺失或无效', en: '{{kind}} skipped: missing or invalid file' },
333
+ 'reload-footer': { zh: '提示:settings.yaml / cordis.patch.yml 由 watcher 自动热重载;cordis.yml 根配置改动需 /restart', en: 'Note: settings.yaml / cordis.patch.yml hot-reload via watchers; cordis.yml root config changes need /restart' },
334
+ 'reload-kind-theme': { zh: '主题', en: 'theme' },
335
+ 'reload-kind-lang': { zh: '语言', en: 'language' },
336
+ 'reload-kind-preset': { zh: '预设', en: 'preset' },
337
+ 'reload-kind-model': { zh: '模型', en: 'model' },
338
+ 'reload-kind-activity': { zh: '活动指示', en: 'activity' },
339
+ // ── /restart (process restart with session resume) ────────────────────
340
+ 'restart-starting': { zh: '正在重启 dsh-tui,完成后自动恢复当前会话……', en: 'Restarting dsh-tui. The session resumes when it comes back…' },
341
+ 'restart-unavailable': { zh: '当前运行方式不支持进程内重启(未挂载重启通道)。', en: 'Restart is unavailable in this launch mode (no restart channel mounted).' },
252
342
  'streaming-folded': { zh: '…(前 {{count}} 字符流式期间已折叠,落定后完整显示)', en: '…(first {{count}} chars folded while streaming; full text renders once the turn settles)' },
253
343
  'vim-not-implemented': { zh: 'vim 模式暂未实现', en: 'vim mode not implemented yet' },
254
344
  'terminal-setup-hint': { zh: '推荐 Windows Terminal(≥110 列、等宽字体、TrueColor)。', en: 'Recommended: Windows Terminal (≥110 columns, monospace, TrueColor).' },
255
- '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.' },
345
+ 'terminal-paste-hint': { zh: '{{mod}}V 或 Alt+V 粘贴文本、文件路径或图片;Ctrl+Shift+V 终端原生粘贴;右键粘贴同样可用;快捷键可在 /settings 修改。', en: '{{mod}}V or Alt+V pastes text, file paths, or images; Ctrl+Shift+V is native terminal paste; right-click paste also works; remappable via /settings.' },
256
346
  'connect-none': { zh: 'DSH 暂无远程连接机制(CC 的 /connect 对应能力未适配)。', en: 'DSH has no remote connection mechanism (CC\'s /connect equivalent is not adapted).' },
257
347
  'theme-switch-failed': { zh: '主题「{{name}}」切换失败(无法写入 ~/.dsh-tui/theme.json)', en: 'Theme "{{name}}" switch failed (cannot write ~/.dsh-tui/theme.json)' },
258
348
  'interrupt-delivered': { zh: '已打断当前回合,{{n}} 条消息立即处理', en: 'Interrupted current turn, {{n}} messages processed immediately' },
@@ -261,6 +351,25 @@ const dict = {
261
351
  'btw-hint-loading': { zh: 'Esc 取消', en: 'Esc cancel' },
262
352
  'btw-hint-done': { zh: '↑/↓ 滚动 · Space/Enter/Esc 关闭 · c 复制', en: '↑/↓ scroll · Space/Enter/Esc dismiss · c copy' },
263
353
  'btw-llm-unavailable': { zh: '侧问不可用(llm 服务未挂载)', en: 'Side question unavailable (llm service not mounted)' },
354
+ 'recap-llm-unavailable': { zh: 'recap 不可用(llm 服务未挂载)', en: 'Recap unavailable (llm service not mounted)' },
355
+ 'recap-no-activity': { zh: '会话还没有可总结的活动', en: 'No session activity to recap yet' },
356
+ 'recap-answering': { zh: '正在总结最近活动…', en: 'Summarizing recent activity…' },
357
+ 'recap-title-label': { zh: '建议标题', en: 'Suggested title' },
358
+ 'recap-apply-title': { zh: '应用', en: 'Apply' },
359
+ 'recap-title-applied': { zh: '已应用', en: 'Applied' },
360
+ 'recap-title-applied-notify': { zh: '已将会话标题设为「{{title}}」', en: 'Session title set to "{{title}}"' },
361
+ 'recap-hint': { zh: '↑/↓ 滚动 · Space/Enter/Esc 关闭 · c 复制{{apply}}', en: '↑/↓ scroll · Space/Enter/Esc dismiss · c copy{{apply}}' },
362
+ 'recap-auto-hint': { zh: '点击展开查看/应用', en: 'Click to expand & apply' },
363
+ 'recap-auto-close': { zh: '关闭', en: 'Dismiss' },
364
+ 'recap-auto-line': { zh: '回顾:{{summary}}', en: 'Recap: {{summary}}' },
365
+ 'recap-panel-title': { zh: '会话回顾', en: 'Session recap' },
366
+ 'recap-panel-subtitle': { zh: '最近活动的快速复盘', en: 'A quick recap of recent activity' },
367
+ 'color-current': { zh: '当前会话颜色 {{name}}', en: 'Current session color {{name}}' },
368
+ 'color-current-none': { zh: '当前会话未设置颜色(用主题默认)', en: 'No session color set (theme default)' },
369
+ 'color-usage': { zh: '用法:/color <{{list}}|reset> —— 颜色按会话保存,resume 后仍在', en: 'Usage: /color <{{list}}|reset> — per-session, survives resume' },
370
+ 'color-reset': { zh: '已清除会话颜色,恢复主题默认', en: 'Session color cleared — back to the theme default' },
371
+ 'color-unknown': { zh: '未知颜色「{{name}}」· 可选:{{list}}', en: 'Unknown color "{{name}}" · available: {{list}}' },
372
+ 'color-set': { zh: '会话颜色已设为 {{name}}', en: 'Session color set to {{name}}' },
264
373
  'exit-press-again': { zh: '再次按 Ctrl+C 退出', en: 'Press Ctrl+C again to exit' },
265
374
  'esc-again-rewind': { zh: '再次按 Esc 时间回溯', en: 'Press Esc again to rewind' },
266
375
  'esc-again-clear': { zh: '再次按 Esc 清空', en: 'Press Esc again to clear' },
@@ -279,12 +388,12 @@ const dict = {
279
388
  // 0.8.3 launcher alignment bridge: /update only replaces the profile
280
389
  // copy; the global `dsh-tui` launcher must be aligned separately.
281
390
  'update-launcher-align-unknown': {
282
- zh: 'Profile 已更新到 v{{version}}。如果你平时使用全局 dsh-tui 命令启动,请同步更新全局启动器:\n npm install -g @deepseek-harness-tui/dsh-tui@{{version}}',
283
- en: 'The profile is now v{{version}}. If you normally launch with the global dsh-tui command, align the global launcher too:\n npm install -g @deepseek-harness-tui/dsh-tui@{{version}}',
391
+ zh: 'Profile 已更新到 v{{version}}。如果你平时使用全局 dsh-tui 命令启动,请同步更新全局启动器:\n npm install -g --legacy-peer-deps @deepseek-harness-tui/dsh-tui@{{version}}\n(--legacy-peer-deps 可绕过 npm 12 的 peer 解析崩溃,全局启动器是瘦壳,跳过全局 peer 解析是安全的)',
392
+ en: 'The profile is now v{{version}}. If you normally launch with the global dsh-tui command, align the global launcher too:\n npm install -g --legacy-peer-deps @deepseek-harness-tui/dsh-tui@{{version}}\n(--legacy-peer-deps works around an npm 12 peer-resolution crash; the global launcher is a thin shim, so skipping global peer resolution is safe.)',
284
393
  },
285
394
  'update-launcher-outdated': {
286
- zh: 'Profile 已更新到 v{{profile}},但全局启动器仍是 v{{launcher}}。请同步更新:\n npm install -g @deepseek-harness-tui/dsh-tui@{{profile}}',
287
- en: 'The profile is now v{{profile}}, but the global launcher is still v{{launcher}}. Align it with:\n npm install -g @deepseek-harness-tui/dsh-tui@{{profile}}',
395
+ zh: 'Profile 已更新到 v{{profile}},但全局启动器仍是 v{{launcher}}。请同步更新:\n npm install -g --legacy-peer-deps @deepseek-harness-tui/dsh-tui@{{profile}}\n(--legacy-peer-deps 可绕过 npm 12 的 peer 解析崩溃,见 #459)',
396
+ en: 'The profile is now v{{profile}}, but the global launcher is still v{{launcher}}. Align it with:\n npm install -g --legacy-peer-deps @deepseek-harness-tui/dsh-tui@{{profile}}\n(--legacy-peer-deps works around an npm 12 peer-resolution crash, see #459.)',
288
397
  },
289
398
  // ── components/ActivityLine.tsx ──────────────────────────────────────
290
399
  'activity-ctx-warn': { zh: '⚠ 上下文', en: '⚠ ctx ' },
@@ -343,25 +452,14 @@ const dict = {
343
452
  'input-editor-failed': { zh: '外部编辑器失败:{{name}}', en: 'External editor failed: {{name}}' },
344
453
  'input-clipboard-read-failed': { zh: '读取剪贴板失败', en: 'Failed to read the clipboard' },
345
454
  'input-clipboard-unavailable': { zh: '无法读取剪贴板:没有可用的 wl-paste / xclip / xsel(未安装或会话不可连接)', en: 'Cannot read clipboard: no usable wl-paste / xclip / xsel (not installed or session unreachable)' },
346
- 'input-clipboard-image-saved': { zh: '剪贴板图片已保存为临时文件,已插入路径', en: 'Clipboard image saved to a temp file; path inserted' },
347
455
  'input-image-pasted': { zh: '已粘贴图片 {{token}}', en: 'Pasted image {{token}}' },
348
456
  'input-image-paste-failed': { zh: '粘贴图片失败:{{err}}', en: 'Could not paste image: {{err}}' },
349
457
  'input-pending-steer-label': { zh: '插话 · 下一步送达', en: 'Steer · delivered next' },
350
458
  'input-pending-queue-label': { zh: '排队 · 回合结束后送达', en: 'Queued · delivered after the turn' },
351
459
  'input-pending-actions-hint': { zh: '撤回 · Esc 打断并立即发送', en: 'Retract · Esc interrupts and sends immediately' },
352
- // ── components/whaleFrames.ts (frame labels) ────────────────────────
353
- 'frame-blink': { zh: '眨眼', en: 'blink' },
354
- 'frame-fin-1': { zh: '动腹鳍1', en: 'fin1' },
355
- 'frame-fin-2': { zh: '动腹鳍2', en: 'fin2' },
356
- 'frame-spout-1': { zh: '喷水花1', en: 'spout1' },
357
- 'frame-spout-2': { zh: '喷水花2', en: 'spout2' },
358
- 'frame-spout-3': { zh: '喷水花3', en: 'spout3' },
359
- 'frame-spout-4': { zh: '喷水花4', en: 'spout4' },
360
- 'frame-spout-5': { zh: '喷水花5', en: 'spout5' },
361
- 'frame-spout-6': { zh: '喷水花6', en: 'spout6' },
362
- 'frame-tail-1': { zh: '摆尾巴1', en: 'tail1' },
363
- 'frame-tail-2': { zh: '摆尾巴2', en: 'tail2' },
364
- 'frame-tail-3': { zh: '摆尾巴3', en: 'tail3' },
460
+ 'input-fold-stats': { zh: '{{lines}} 行 · {{chars}} 字', en: '{{lines}} lines · {{chars}} chars' },
461
+ 'input-fold-hover': { zh: '悬停查看', en: 'hover to peek' },
462
+ 'input-fold-peek-footer': { zh: '… 共 {{lines}} 行 · 点击展开编辑', en: '… {{lines}} lines total · click to edit' },
365
463
  // ── components/SuggestionCard.tsx(/ 命令菜单 · @ 文件菜单)─────────
366
464
  'sugg-commands-title': { zh: '命令', en: 'commands' },
367
465
  'sugg-files-title': { zh: '文件', en: 'files' },
@@ -378,8 +476,11 @@ const dict = {
378
476
  'sugg-effort-level-desc': { zh: '思考强度档位', en: 'Reasoning effort level' },
379
477
  'sugg-activity-frames-desc': { zh: '列出或切换动画帧预设', en: 'List or switch frame presets' },
380
478
  'sugg-activity-frame-desc': { zh: '动画帧预设', en: 'Animation frame preset' },
479
+ 'sugg-color-reset-desc': { zh: '清除会话颜色,恢复主题默认', en: 'Clear the session color' },
480
+ 'sugg-color-name-desc': { zh: '会话强调色', en: 'Session accent color' },
381
481
  // ── dsh-adapter/plugin.ts(/settings 全屏设置)───────────────────────
382
482
  'settings-fullscreen-restart': { zh: '全屏设置已保存,重启 dsh-tui 后生效', en: 'Fullscreen preference saved — restart dsh-tui to apply' },
483
+ 'settings-fullscreen-migrated': { zh: '全屏已是出厂默认(已清除更新前的 inline 选择);偏好 inline 可在 /settings 改回', en: 'Fullscreen is now the factory default (pre-update inline choice cleared); prefer inline? Switch back in /settings' },
383
484
  // ── components/HelpMenu.tsx ─────────────────────────────────────────
384
485
  'help-for-commands': { zh: '/ 查看命令', en: '/ for commands' },
385
486
  'help-this-help': { zh: '? 查看本帮助', en: '? for this help' },
@@ -480,19 +581,31 @@ const dict = {
480
581
  'session-hint-list-short': { zh: '**Enter** 恢复 · Tab 预览 · Esc 退出', en: '**Enter** resume · Tab preview · Esc exit' },
481
582
  // ── picker 通用快捷键提示(整句本地化,zh 不用 "to" 结构;**段** 渲染为粗体主快捷键)─
482
583
  'hint-confirm-exit': { zh: '**Enter** 确认 · Esc 退出', en: '**Enter** to confirm · Esc to exit' },
483
- 'hint-confirm-cancel': { zh: '**Enter** 确认 · Esc 取消', en: '**Enter** to confirm · Esc to cancel' },
484
584
  'hint-select-exit': { zh: '**Enter** 选择 · Esc 退出', en: '**Enter** to select · Esc to exit' },
485
585
  'hint-fill-exit': { zh: '**Enter** 填入命令 · Esc 退出', en: '**Enter** to insert · Esc to exit' },
486
586
  'hint-rewind-back': { zh: '**Enter** 回退 · Esc 返回', en: '**Enter** to rewind · Esc to back' },
487
587
  'statusline-hint-select': { zh: 'esc 返回输入', en: 'esc to return to input' },
488
588
  'statusline-hint-working': { zh: 'esc 中断', en: 'esc to interrupt' },
489
589
  'statusline-hint-shortcuts': { zh: '? 查看快捷键', en: '? for shortcuts' },
590
+ // ── 底栏字段 hover 明细(补充行读出;技术标签 ctx/free/read 等保持不译)──
591
+ 'status-detail-of-window': { zh: '的窗口', en: 'of window' },
592
+ 'status-detail-session-id': { zh: '会话日志目录与此 id 同名', en: 'the session log directory is named after this id' },
490
593
  'hint-ext-dialog-input': { zh: '**Enter** 确认 · Esc 取消', en: '**Enter** to confirm · Esc to cancel' },
491
594
  'hint-adjust-done': { zh: '**←/→** 调整 · Enter/Esc 完成', en: '**←/→** to adjust · Enter/Esc to done' },
492
595
  'hint-history-search': { zh: '↑/↓ 选择 · **Enter** 确认 · Esc 取消', en: '↑/↓ to navigate · **Enter** to select · Esc to cancel' },
493
596
  'hint-expand-ctrl-o': { zh: '(ctrl+o 展开)', en: '(ctrl+o to expand)' },
597
+ // ── components/FileActionsPanel.tsx(点击文件路径弹出的操作菜单)──
598
+ 'file-actions-title': { zh: '文件操作', en: 'File actions' },
599
+ 'file-actions-open': { zh: '打开文件', en: 'Open file' },
600
+ 'file-actions-open-dir': { zh: '打开文件夹', en: 'Open folder' },
601
+ 'file-actions-reveal': { zh: '打开所在文件夹', en: 'Reveal in folder' },
602
+ 'file-actions-copy': { zh: '复制绝对路径', en: 'Copy absolute path' },
494
603
  // ── components/ModelPicker.tsx / ThemePicker.tsx / ActivityPicker.tsx / EffortSlider.tsx ──
495
604
  'picker-title-model': { zh: '模型', en: 'Model' },
605
+ 'picker-group-recent': { zh: '最近使用', en: 'Recently used' },
606
+ 'picker-group-count': { zh: '{{count}} 个模型', en: '{{count}} models' },
607
+ 'hint-model-groups': { zh: '**Enter** 查看模型 · Esc 退出', en: '**Enter** to view models · Esc to exit' },
608
+ 'hint-model-back': { zh: '**Enter** 切换模型 · Esc/⌫ 返回上级', en: '**Enter** to switch · Esc/⌫ to go back' },
496
609
  'picker-title-skills': { zh: '技能', en: 'Skills' },
497
610
  'skills-loading': { zh: '正在加载技能', en: 'Loading skills' },
498
611
  'skills-loading-subtitle': { zh: '正在查询技能注册表…', en: 'Querying the skill registry…' },
@@ -508,6 +621,7 @@ const dict = {
508
621
  'skills-source-custom': { zh: '自定义', en: 'custom' },
509
622
  'picker-title-theme': { zh: '颜色主题', en: 'Color theme' },
510
623
  'picker-title-activity': { zh: '指示器预设', en: 'Indicator preset' },
624
+ 'picker-title-color': { zh: '会话强调色', en: 'Session accent color' },
511
625
  'picker-title-effort': { zh: '推理强度', en: 'Reasoning effort' },
512
626
  'model-loading': { zh: '正在加载模型', en: 'Loading models' },
513
627
  'model-loading-subtitle': { zh: '正在查询 provider…', en: 'Querying the provider…' },
@@ -536,10 +650,6 @@ const dict = {
536
650
  zh: '命令 "/{{name}}" 的调用已被拒绝——注册它的插件 "{{owner}}" 已被撤销 commands.invoke',
537
651
  en: 'Command "/{{name}}" invocation denied — its owner plugin "{{owner}}" lost commands.invoke',
538
652
  },
539
- 'plugins-check-tui-extension': {
540
- zh: '注:该 manifest 依赖 TUI 宿主扩展面(tui.dsh/v1alpha1 DecisionEvents / session.*.intercept 权限),判定基于宿主扩展覆盖层而非 vendored 社区注册表。',
541
- en: 'Note: this manifest relies on the TUI host-extension surface (tui.dsh/v1alpha1 DecisionEvents / session.*.intercept permissions); the verdict used the host extension overlay, not the vendored community registry.',
542
- },
543
653
  // /plugins 诊断面(C-070 信任披露 + 协商诊断)
544
654
  'plugins-trust-banner': {
545
655
  zh: '插件与宿主同进程运行:授权是行为约束而非安全隔离;通过校验 ≠ 插件安全(C-070)。',
@@ -550,7 +660,7 @@ const dict = {
550
660
  'plugins-matrix-note': { zh: '授权矩阵(✓ 允许 / · 拒绝;仅显示有足迹的插件——授权文件、效果台账与存储目录的并集):', en: 'Grant matrix (✓ allowed / · denied; plugins with footprints only — union of the grants file, effect ledger, and storage directory):' },
551
661
  'plugins-matrix-no-registry': { zh: '(权限注册表不可用)', en: '(permission registry unavailable)' },
552
662
  'plugins-matrix-empty': { zh: '(暂无插件足迹)', en: '(no plugin footprints yet)' },
553
- 'plugins-footprint-overflow': { zh: '…另有 {{count}} 个插件未显示', en: '…{{count}} more plugin(s) not shown' },
663
+ 'plugins-footprint-overflow': { zh: '…另有 {{count}} 个插件未显示', en: { one: '…{{count}} more plugin not shown', other: '…{{count}} more plugins not shown' } },
554
664
  'plugins-ledger-empty': { zh: '效果台账为空。', en: 'The effect ledger is empty.' },
555
665
  'plugins-ledger-header': { zh: '效果台账({{file}})尾 5 条:', en: 'Effect ledger ({{file}}), last 5 records:' },
556
666
  'plugins-unknown-subcommand': { zh: '未知子命令:{{sub}}(支持:check <路径>)', en: 'Unknown subcommand: {{sub}} (supported: check <path>)' },
@@ -613,6 +723,8 @@ const dict = {
613
723
  'question-hint-enter': { zh: 'Enter 提交', en: 'Enter submit' },
614
724
  'question-hint-back': { zh: '↑ 返回选项', en: '↑ back to options' },
615
725
  'question-hint-esc': { zh: 'Esc 中断', en: 'Esc cancel' },
726
+ 'question-hint-previous': { zh: 'Esc 上一题', en: 'Esc previous question' },
727
+ 'question-hint-cancel': { zh: 'Ctrl+C 取消整批', en: 'Ctrl+C cancel batch' },
616
728
  'question-hint-selected': { zh: '已选 {{n}}', en: 'Selected {{n}}' },
617
729
  'question-hint-select': { zh: '↑/↓ 选择', en: '↑/↓ select' },
618
730
  'question-hint-multi': { zh: 'Space 多选', en: 'Space multi-select' },
@@ -634,18 +746,14 @@ const dict = {
634
746
  'subagent-count-running': { zh: '运行中', en: 'running' },
635
747
  'subagent-count-completed': { zh: '已完成', en: 'completed' },
636
748
  'subagent-count-failed': { zh: '失败', en: 'failed' },
637
- 'subagent-running-label': { zh: '运行中', en: 'Running' },
638
749
  'subagent-started': { zh: '开始时间', en: 'Started' },
639
750
  'subagent-completed': { zh: '完成时间', en: 'Completed' },
640
- 'subagent-id': { zh: 'ID', en: 'ID' },
641
751
  'subagent-error-label': { zh: '错误', en: 'Error' },
642
752
  'subagent-output-label': { zh: '输出', en: 'Output' },
643
753
  'subagent-no-output': { zh: '暂无输出', en: 'No output yet' },
644
754
  'subagent-dashboard-title': { zh: ' 子代理面板 ', en: ' Subagent Dashboard ' },
645
755
  'subagent-dashboard-hint-basic': { zh: '↑/↓ 浏览 · Esc 关闭', en: '↑/↓ browse · Esc close' },
646
756
  'subagent-dashboard-hint-detail': { zh: '↑/↓ 选择 · Enter 查看详情 · Esc 关闭', en: '↑/↓ select · Enter view detail · Esc close' },
647
- 'subagent-detail-hint-basic': { zh: '↑/↓ 滚动 · Enter/Esc 返回', en: '↑/↓ scroll · Enter/Esc back' },
648
- 'subagent-detail-hint-enhanced': { zh: '↑/↓ 滚动 · X 中断 · Esc 返回', en: '↑/↓ scroll · X interrupt · Esc back' },
649
757
  'subagent-card-prefix': { zh: '子代理:', en: 'Subagent: ' },
650
758
  'subagent-tab-summary': { zh: '摘要', en: 'Summary' },
651
759
  'subagent-no-summary': { zh: '暂无摘要', en: 'No summary yet' },
@@ -707,6 +815,25 @@ const dict = {
707
815
  'provider-q-switch': { zh: '立即切换到新 provider?', en: 'Switch to the new provider now?' },
708
816
  'provider-opt-switch-now': { zh: '切换到 {{model}}', en: 'Switch to {{model}}' },
709
817
  'provider-opt-switch-keep': { zh: '保持当前模型', en: 'Keep the current model' },
818
+ // /provider OAuth 分支(dsh-auth 等插件挂载 ctx.dshAuth 时出现)
819
+ 'provider-opt-oauth': { zh: '订阅账号登录(OAuth)', en: 'Subscription sign-in (OAuth)' },
820
+ 'provider-opt-oauth-desc': { zh: '用 ChatGPT / Claude / Grok 等官方订阅账号登录,无需 API key', en: 'Sign in with an official subscription (ChatGPT / Claude / Grok) — no API key' },
821
+ 'provider-q-oauth': { zh: '登录哪个订阅账号?', en: 'Sign in to which subscription?' },
822
+ 'provider-oauth-state-in': { zh: '已登录 · 令牌到期 {{time}}', en: 'Signed in · token expires {{time}}' },
823
+ 'provider-oauth-state-expired': { zh: '已登录但令牌已过期,重新登录即可恢复', en: 'Signed in but the token expired — sign in again to restore' },
824
+ 'provider-q-oauth-signed': { zh: '{{provider}} 已登录,接下来?', en: '{{provider}} is signed in — what next?' },
825
+ 'provider-opt-oauth-relogin': { zh: '重新登录', en: 'Sign in again' },
826
+ 'provider-opt-oauth-relogin-desc': { zh: '更换账号或刷新已有凭据', en: 'Switch accounts or refresh the stored credential' },
827
+ 'provider-opt-oauth-logout': { zh: '登出', en: 'Sign out' },
828
+ 'provider-opt-oauth-logout-desc': { zh: '删除本地保存的 OAuth 凭据', en: 'Remove the locally stored OAuth credential' },
829
+ 'provider-oauth-none': { zh: '没有可 OAuth 登录的 provider(检查 dsh-auth 插件是否挂载)', en: 'No OAuth-capable providers (check whether the dsh-auth plugin is mounted)' },
830
+ 'provider-oauth-login-ok': { zh: '{{provider}} 登录成功', en: 'Signed in to {{provider}}' },
831
+ 'provider-oauth-login-failed': { zh: 'OAuth 登录失败 · {{{err}}}', en: 'OAuth sign-in failed · {{{err}}}' },
832
+ 'provider-oauth-logout-ok': { zh: '{{provider}} 已登出', en: 'Signed out of {{provider}}' },
833
+ 'provider-line-oauth-provider': { zh: '路由:{{provider}}', en: 'Route: {{provider}}' },
834
+ 'provider-line-oauth-flow': { zh: '登录方式:{{flow}}', en: 'Sign-in: {{flow}}' },
835
+ 'provider-line-oauth-expires': { zh: '令牌到期:{{time}}', en: 'Token expires: {{time}}' },
836
+ 'provider-line-oauth-out': { zh: '已登出,本地 OAuth 凭据已删除', en: 'Signed out — the stored OAuth credential was removed' },
710
837
  // ── commands.ts — slash-command descriptions ─────────────────────────
711
838
  // zh-only on purpose: the English text stays in `LOCAL_COMMANDS` (and in
712
839
  // the DSH registry for external commands) as the single source of truth,
@@ -719,15 +846,19 @@ const dict = {
719
846
  'cmd-desc-compact': { zh: '压缩会话历史' },
720
847
  'cmd-desc-resume': { zh: '恢复历史会话' },
721
848
  'cmd-desc-rename': { zh: '重命名当前会话' },
849
+ 'cmd-desc-recap': { zh: '生成最近会话活动摘要(可应用建议标题)' },
722
850
  'cmd-desc-quit': { zh: '退出 dsh-tui' },
723
851
  'cmd-desc-q': { zh: '退出 dsh-tui' },
724
852
  'cmd-desc-rewind': { zh: '回退会话到历史消息' },
853
+ 'cmd-desc-tree': { zh: '浏览会话分叉树(回退/分叉/切分支)' },
854
+ 'cmd-desc-fork': { zh: '把当前会话分叉为可恢复副本' },
725
855
  'cmd-desc-export': { zh: '导出会话为 Markdown 文件' },
726
856
  // Session / environment
727
857
  'cmd-desc-context': { zh: '查看已加载的上下文明细' },
728
858
  'cmd-desc-status': { zh: '查看会话状态' },
729
859
  'cmd-desc-cost': { zh: '查看会话 token 用量' },
730
860
  'cmd-desc-config': { zh: '查看 dsh-tui 配置来源' },
861
+ 'cmd-desc-reload': { zh: '重读偏好文件并立即生效' },
731
862
  'cmd-desc-settings': { zh: '查看和编辑插件设置' },
732
863
  'cmd-desc-doctor': { zh: '运行环境检查' },
733
864
  'cmd-desc-init': { zh: '在工作目录创建 AGENTS.md' },
@@ -736,6 +867,7 @@ const dict = {
736
867
  'cmd-desc-activity': { zh: '切换工作状态指示器预设' },
737
868
  'cmd-desc-preset': { zh: '切换 Agent 预设(含梁神模式)' },
738
869
  'cmd-desc-theme': { zh: '切换配色主题(auto 跟随系统,或内置/自定义)' },
870
+ 'cmd-desc-color': { zh: '设置当前会话强调色(输入框边框与会话标签)' },
739
871
  'cmd-desc-lang': { zh: '切换界面语言(en / zh)' },
740
872
  'cmd-desc-model': { zh: '查看当前模型' },
741
873
  'cmd-desc-thinking': { zh: '显示或隐藏思考过程' },
@@ -768,6 +900,7 @@ const dict = {
768
900
  'cmd-desc-workspace-open': { zh: '打开路径或工作区 URI', en: 'Open a path or workspace URI' },
769
901
  // Help / exit
770
902
  'cmd-desc-help': { zh: '查看快捷键与命令' },
903
+ 'cmd-desc-restart': { zh: '重启 dsh-tui 并恢复当前会话' },
771
904
  'cmd-desc-exit': { zh: '退出 dsh-tui' },
772
905
  // Registry-injected (external) commands — zh only; en falls back to the
773
906
  // registry's own description, and unlisted externals always fall back.
@@ -819,24 +952,7 @@ const dict = {
819
952
  zh: '**j/k** 翻页 · **enter/esc** 收起 · **q** 退出',
820
953
  en: '**j/k** page · **enter/esc** collapse · **q** exit',
821
954
  },
822
- 'traj-empty': { zh: '暂无轨迹事件', en: 'No trajectory events yet' },
823
955
  'traj-hint-failure': { zh: '{{key}} 看完整轨迹', en: '{{key}} for the full trajectory' },
824
- // ── subagent UI ──────────────────────────────────────────────────────
825
- 'subagent.unnamed': { zh: '未命名子代理', en: 'Unnamed subagent' },
826
- 'subagent.no-model': { zh: '未知模型', en: 'Unknown model' },
827
- 'subagent.status.running': { zh: '运行中', en: 'Running' },
828
- 'subagent.status.completed': { zh: '已完成', en: 'Completed' },
829
- 'subagent.status.failed': { zh: '失败', en: 'Failed' },
830
- 'subagent.status.pending': { zh: '等待中', en: 'Pending' },
831
- 'subagent.dashboard.title': { zh: '子代理面板', en: 'Subagent Dashboard' },
832
- 'subagent.dashboard.stats': { zh: '运行中: {{running}} · 已完成: {{completed}} · 失败: {{failed}}', en: 'Running: {{running}} · Completed: {{completed}} · Failed: {{failed}}' },
833
- 'subagent.dashboard.empty': { zh: '暂无子代理', en: 'No subagents yet' },
834
- 'subagent.dashboard.help': { zh: '↑↓ 选择 · Enter 查看详情 · Esc 返回', en: '↑↓ select · Enter view details · Esc back' },
835
- 'subagent.detail.not-found': { zh: '子代理未找到', en: 'Subagent not found' },
836
- 'subagent.detail.press-esc': { zh: '按 Esc 返回', en: 'Press Esc to go back' },
837
- 'subagent.detail.output': { zh: '输出', en: 'Output' },
838
- 'subagent.detail.no-output': { zh: '暂无输出', en: 'No output yet' },
839
- 'subagent.detail.help': { zh: 'Esc 返回面板', en: 'Esc back to dashboard' },
840
956
  };
841
957
  /** The active language, module-level so non-React modules (channel.ts,
842
958
  * loaded-context.ts) resolve strings without a context. Defaults to `zh`
@@ -874,7 +990,24 @@ export function isLang(value) {
874
990
  */
875
991
  export function t(key, params = {}) {
876
992
  const entry = dict[key];
877
- const template = entry?.[activeLang] ?? key;
993
+ return substitute(pickText(entry?.[activeLang], params) ?? key, params);
994
+ }
995
+ // Cached per shipped language; CLDR-backed and built into Node, so zh always
996
+ // selects `other` and en selects `one` exactly at count 1.
997
+ const pluralRules = {
998
+ zh: new Intl.PluralRules('zh'),
999
+ en: new Intl.PluralRules('en'),
1000
+ };
1001
+ /** Resolve plural forms to one template using the `count` param. */
1002
+ function pickText(text, params) {
1003
+ if (text === undefined || typeof text === 'string')
1004
+ return text;
1005
+ const count = Number(params.count);
1006
+ const category = pluralRules[activeLang].select(Number.isFinite(count) ? count : 0);
1007
+ return category === 'one' ? text.one : text.other;
1008
+ }
1009
+ /** Substitute `{{name}}` placeholders, leaving unknown names visible. */
1010
+ function substitute(template, params) {
878
1011
  return template.replace(/\{\{(\w+)\}\}/g, (match, name) => name in params ? String(params[name]) : match);
879
1012
  }
880
1013
  /**
@@ -889,9 +1022,10 @@ export function t(key, params = {}) {
889
1022
  */
890
1023
  export function tOr(key, fallback, params = {}) {
891
1024
  const entry = dict[key];
892
- const template = entry?.[activeLang] ?? fallback;
893
- return template.replace(/\{\{(\w+)\}\}/g, (match, name) => name in params ? String(params[name]) : match);
1025
+ return substitute(pickText(entry?.[activeLang], params) ?? fallback, params);
894
1026
  }
1027
+ /** Read-only view of the dictionary for audits (scripts/verify-i18n.ts). */
1028
+ export const i18nDict = dict;
895
1029
  // ── persistence (~/.dsh-tui/lang.json) ─────────────────────────────────
896
1030
  /**
897
1031
  * Parse a persisted `{ lang }` value; anything else yields undefined.
@@ -931,12 +1065,16 @@ export function writeLangPref(lang, dir = PREFS_DIR) {
931
1065
  }
932
1066
  /**
933
1067
  * Guess the user's language from the OS locale (`LC_ALL`, `LC_MESSAGES`,
934
- * `LANG`), defaulting to `zh`. Only consulted when nothing else (env var,
935
- * cordis.yml `lang`, persisted `/lang` choice) pinned a language.
936
- * The POSIX/C locale means "no locale selected" and conventionally maps to
937
- * English — importantly it is what CI runners (LANG=C.UTF-8) report, so
938
- * tests asserting English UI copy stay deterministic. An absent locale
939
- * variable (typical on Windows) still defaults to `zh`.
1068
+ * `LANG`). Only consulted when nothing else (env var, cordis.yml `lang`,
1069
+ * persisted `/lang` choice) pinned a language. `zh*` maps to zh; every
1070
+ * other stated locale (en, but also fr/de/ja/…) maps to en — English is
1071
+ * the lingua-franca fallback for a locale we don't ship, and a German
1072
+ * user must not get a Chinese UI. The POSIX/C locale means "no locale
1073
+ * selected" and conventionally maps to English — importantly it is what
1074
+ * CI runners (LANG=C.UTF-8) report, so tests asserting English UI copy
1075
+ * stay deterministic. Only an ABSENT locale (typical on Windows, where
1076
+ * these POSIX vars don't exist and imply nothing about the user) keeps
1077
+ * the zh default.
940
1078
  */
941
1079
  export function detectLocaleLang() {
942
1080
  // `||` (not `??`): an EMPTY locale variable means "unset" and must fall
@@ -946,13 +1084,9 @@ export function detectLocaleLang() {
946
1084
  process.env.LANG ||
947
1085
  '';
948
1086
  const locale = raw.split('.')[0]?.toLowerCase() ?? '';
949
- if (locale.startsWith('zh'))
1087
+ if (locale === '')
950
1088
  return 'zh';
951
- if (locale.startsWith('en'))
952
- return 'en';
953
- if (locale === 'c' || locale === 'posix')
954
- return 'en';
955
- return 'zh';
1089
+ return locale.startsWith('zh') ? 'zh' : 'en';
956
1090
  }
957
1091
  /**
958
1092
  * Resolve the startup language: `DSH_TUI_LANG` when it holds a valid value
@@ -1 +1 @@
1
- {"version":3,"file":"log-update.d.ts","sourceRoot":"","sources":["../../../src/ink/log-update.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAiB,KAAK,EAAE,MAAM,YAAY,CAAA;AAE5D,OAAO,EASL,KAAK,SAAS,EAGf,MAAM,aAAa,CAAA;AA4BpB,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;CACrB,CAAA;AAKD;;;GAGG;AACH,qBAAa,SAAS;IAGR,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,KAAK,CAAO;gBAES,OAAO,EAAE,OAAO;IAQ7C;;;;;;;;;;;;;;;;;OAiBG;IACH,uBAAuB,IAAI,IAAI;IAI/B;;;;;OAKG;IACH,+BAA+B,CAAC,SAAS,EAAE,KAAK,GAAG,IAAI;IASvD,+HAA+H;IAC/H,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,eAAe;IAiDvB,OAAO,CAAC,mBAAmB;IAS3B;;;;;;;;OAQG;IACH,MAAM,CACJ,IAAI,EAAE,KAAK,EACX,IAAI,EAAE,KAAK,EACX,SAAS,UAAQ,EACjB,WAAW,UAAO,GACjB,IAAI;CAsfR"}
1
+ {"version":3,"file":"log-update.d.ts","sourceRoot":"","sources":["../../../src/ink/log-update.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAiB,KAAK,EAAE,MAAM,YAAY,CAAA;AAE5D,OAAO,EASL,KAAK,SAAS,EAGf,MAAM,aAAa,CAAA;AA4BpB,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;CACrB,CAAA;AAKD;;;GAGG;AACH,qBAAa,SAAS;IAGR,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,KAAK,CAAO;gBAES,OAAO,EAAE,OAAO;IAQ7C;;;;;;;;;;;;;;;;;OAiBG;IACH,uBAAuB,IAAI,IAAI;IAI/B;;;;;OAKG;IACH,+BAA+B,CAAC,SAAS,EAAE,KAAK,GAAG,IAAI;IASvD,+HAA+H;IAC/H,KAAK,IAAI,IAAI;IASb,OAAO,CAAC,eAAe;IAiDvB,OAAO,CAAC,mBAAmB;IAS3B;;;;;;;;OAQG;IACH,MAAM,CACJ,IAAI,EAAE,KAAK,EACX,IAAI,EAAE,KAAK,EACX,SAAS,UAAQ,EACjB,WAAW,UAAO,GACjB,IAAI;CA6gBR"}