@jingyi0605/codingns4dsh 0.2.0-beta.2 → 0.2.0-rc.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 (420) hide show
  1. package/README.en.md +4 -4
  2. package/README.md +7 -5
  3. package/assets/provider-icons/minimax-code.svg +4 -0
  4. package/assets/provider-icons/zcode.svg +14 -0
  5. package/data/build/dist/client/account-bar.d.ts +2 -1
  6. package/data/build/dist/client/account-bar.d.ts.map +1 -1
  7. package/data/build/dist/client/account-bar.js +21 -16
  8. package/data/build/dist/client/account-bar.js.map +1 -1
  9. package/data/build/dist/client/bundle.js +4172 -1540
  10. package/data/build/dist/client/bundle.js.map +1 -1
  11. package/data/build/dist/client/cli-slots.d.ts.map +1 -1
  12. package/data/build/dist/client/cli-slots.js +20 -12
  13. package/data/build/dist/client/cli-slots.js.map +1 -1
  14. package/data/build/dist/client/debug/ui.d.ts +2 -1
  15. package/data/build/dist/client/debug/ui.d.ts.map +1 -1
  16. package/data/build/dist/client/debug/ui.js +39 -33
  17. package/data/build/dist/client/debug/ui.js.map +1 -1
  18. package/data/build/dist/client/delegate-command.d.ts +16 -0
  19. package/data/build/dist/client/delegate-command.d.ts.map +1 -0
  20. package/data/build/dist/client/delegate-command.js +138 -0
  21. package/data/build/dist/client/delegate-command.js.map +1 -0
  22. package/data/build/dist/client/delegate-plan.d.ts +31 -0
  23. package/data/build/dist/client/delegate-plan.d.ts.map +1 -0
  24. package/data/build/dist/client/delegate-plan.js +59 -0
  25. package/data/build/dist/client/delegate-plan.js.map +1 -0
  26. package/data/build/dist/client/delegate-ui-dom.d.ts +40 -0
  27. package/data/build/dist/client/delegate-ui-dom.d.ts.map +1 -0
  28. package/data/build/dist/client/delegate-ui-dom.js +363 -0
  29. package/data/build/dist/client/delegate-ui-dom.js.map +1 -0
  30. package/data/build/dist/client/external-tool-stream.d.ts.map +1 -1
  31. package/data/build/dist/client/external-tool-stream.js +44 -36
  32. package/data/build/dist/client/external-tool-stream.js.map +1 -1
  33. package/data/build/dist/client/features/cli-adapters.d.ts +7 -2
  34. package/data/build/dist/client/features/cli-adapters.d.ts.map +1 -1
  35. package/data/build/dist/client/features/cli-adapters.js +52 -103
  36. package/data/build/dist/client/features/cli-adapters.js.map +1 -1
  37. package/data/build/dist/client/features/debug.d.ts.map +1 -1
  38. package/data/build/dist/client/features/debug.js +5 -3
  39. package/data/build/dist/client/features/debug.js.map +1 -1
  40. package/data/build/dist/client/features/file-management.d.ts.map +1 -1
  41. package/data/build/dist/client/features/file-management.js +7 -4
  42. package/data/build/dist/client/features/file-management.js.map +1 -1
  43. package/data/build/dist/client/features/lan-access-panel.js +10 -10
  44. package/data/build/dist/client/features/lan-access-panel.js.map +1 -1
  45. package/data/build/dist/client/features/lan-access.d.ts.map +1 -1
  46. package/data/build/dist/client/features/lan-access.js +8 -3
  47. package/data/build/dist/client/features/lan-access.js.map +1 -1
  48. package/data/build/dist/client/features/login-protection-panel.d.ts.map +1 -1
  49. package/data/build/dist/client/features/login-protection-panel.js +9 -7
  50. package/data/build/dist/client/features/login-protection-panel.js.map +1 -1
  51. package/data/build/dist/client/features/login-protection.js +2 -2
  52. package/data/build/dist/client/features/login-protection.js.map +1 -1
  53. package/data/build/dist/client/features/mobile-access.d.ts.map +1 -1
  54. package/data/build/dist/client/features/mobile-access.js +6 -2
  55. package/data/build/dist/client/features/mobile-access.js.map +1 -1
  56. package/data/build/dist/client/features/peer-host.d.ts.map +1 -1
  57. package/data/build/dist/client/features/peer-host.js +115 -11
  58. package/data/build/dist/client/features/peer-host.js.map +1 -1
  59. package/data/build/dist/client/features/reverse-proxy.js +2 -2
  60. package/data/build/dist/client/features/reverse-proxy.js.map +1 -1
  61. package/data/build/dist/client/features/terminal-enhancement.js +2 -2
  62. package/data/build/dist/client/features/terminal-enhancement.js.map +1 -1
  63. package/data/build/dist/client/features/workspace-session-enhancement-panel.js +1 -1
  64. package/data/build/dist/client/features/workspace-session-enhancement-panel.js.map +1 -1
  65. package/data/build/dist/client/features/workspace-session-enhancement.d.ts.map +1 -1
  66. package/data/build/dist/client/features/workspace-session-enhancement.js +8 -3
  67. package/data/build/dist/client/features/workspace-session-enhancement.js.map +1 -1
  68. package/data/build/dist/client/file-management-dom.d.ts +3 -0
  69. package/data/build/dist/client/file-management-dom.d.ts.map +1 -1
  70. package/data/build/dist/client/file-management-dom.js +41 -30
  71. package/data/build/dist/client/file-management-dom.js.map +1 -1
  72. package/data/build/dist/client/git-management.d.ts +2 -0
  73. package/data/build/dist/client/git-management.d.ts.map +1 -1
  74. package/data/build/dist/client/git-management.js +82 -74
  75. package/data/build/dist/client/git-management.js.map +1 -1
  76. package/data/build/dist/client/git-workspace-events.d.ts +7 -0
  77. package/data/build/dist/client/git-workspace-events.d.ts.map +1 -0
  78. package/data/build/dist/client/git-workspace-events.js +32 -0
  79. package/data/build/dist/client/git-workspace-events.js.map +1 -0
  80. package/data/build/dist/client/index.d.ts +2 -0
  81. package/data/build/dist/client/index.d.ts.map +1 -1
  82. package/data/build/dist/client/index.js +6 -5
  83. package/data/build/dist/client/index.js.map +1 -1
  84. package/data/build/dist/client/locale.d.ts +7 -0
  85. package/data/build/dist/client/locale.d.ts.map +1 -1
  86. package/data/build/dist/client/locale.js +80 -36
  87. package/data/build/dist/client/locale.js.map +1 -1
  88. package/data/build/dist/client/locales/debug.d.ts +9 -0
  89. package/data/build/dist/client/locales/debug.d.ts.map +1 -0
  90. package/data/build/dist/client/locales/debug.js +163 -0
  91. package/data/build/dist/client/locales/debug.js.map +1 -0
  92. package/data/build/dist/client/locales/fileWorkspace.d.ts +9 -0
  93. package/data/build/dist/client/locales/fileWorkspace.d.ts.map +1 -0
  94. package/data/build/dist/client/locales/fileWorkspace.js +139 -0
  95. package/data/build/dist/client/locales/fileWorkspace.js.map +1 -0
  96. package/data/build/dist/client/locales/git.d.ts +9 -0
  97. package/data/build/dist/client/locales/git.d.ts.map +1 -0
  98. package/data/build/dist/client/locales/git.js +223 -0
  99. package/data/build/dist/client/locales/git.js.map +1 -0
  100. package/data/build/dist/client/locales/panels.d.ts +9 -0
  101. package/data/build/dist/client/locales/panels.d.ts.map +1 -0
  102. package/data/build/dist/client/locales/panels.js +33 -0
  103. package/data/build/dist/client/locales/panels.js.map +1 -0
  104. package/data/build/dist/client/locales/peerHost.d.ts +9 -0
  105. package/data/build/dist/client/locales/peerHost.d.ts.map +1 -0
  106. package/data/build/dist/client/locales/peerHost.js +153 -0
  107. package/data/build/dist/client/locales/peerHost.js.map +1 -0
  108. package/data/build/dist/client/locales/peerHostWorkspace.d.ts +9 -0
  109. package/data/build/dist/client/locales/peerHostWorkspace.d.ts.map +1 -0
  110. package/data/build/dist/client/locales/peerHostWorkspace.js +69 -0
  111. package/data/build/dist/client/locales/peerHostWorkspace.js.map +1 -0
  112. package/data/build/dist/client/locales/terminalAuth.d.ts +9 -0
  113. package/data/build/dist/client/locales/terminalAuth.d.ts.map +1 -0
  114. package/data/build/dist/client/locales/terminalAuth.js +67 -0
  115. package/data/build/dist/client/locales/terminalAuth.js.map +1 -0
  116. package/data/build/dist/client/locales/usage.d.ts +9 -0
  117. package/data/build/dist/client/locales/usage.d.ts.map +1 -0
  118. package/data/build/dist/client/locales/usage.js +195 -0
  119. package/data/build/dist/client/locales/usage.js.map +1 -0
  120. package/data/build/dist/client/mobile-session-interaction.d.ts +44 -0
  121. package/data/build/dist/client/mobile-session-interaction.d.ts.map +1 -0
  122. package/data/build/dist/client/mobile-session-interaction.js +291 -0
  123. package/data/build/dist/client/mobile-session-interaction.js.map +1 -0
  124. package/data/build/dist/client/mobile-sidebar-rail-dom.d.ts +10 -2
  125. package/data/build/dist/client/mobile-sidebar-rail-dom.d.ts.map +1 -1
  126. package/data/build/dist/client/mobile-sidebar-rail-dom.js +14 -6
  127. package/data/build/dist/client/mobile-sidebar-rail-dom.js.map +1 -1
  128. package/data/build/dist/client/peer-host-connection-button.d.ts +14 -1
  129. package/data/build/dist/client/peer-host-connection-button.d.ts.map +1 -1
  130. package/data/build/dist/client/peer-host-connection-button.js +12 -4
  131. package/data/build/dist/client/peer-host-connection-button.js.map +1 -1
  132. package/data/build/dist/client/peer-host-management-panel.d.ts +3 -0
  133. package/data/build/dist/client/peer-host-management-panel.d.ts.map +1 -1
  134. package/data/build/dist/client/peer-host-management-panel.js +83 -79
  135. package/data/build/dist/client/peer-host-management-panel.js.map +1 -1
  136. package/data/build/dist/client/peer-host-native-projection.d.ts +1 -0
  137. package/data/build/dist/client/peer-host-native-projection.d.ts.map +1 -1
  138. package/data/build/dist/client/peer-host-native-projection.js +5 -0
  139. package/data/build/dist/client/peer-host-native-projection.js.map +1 -1
  140. package/data/build/dist/client/peer-host-scoped-client.js +5 -5
  141. package/data/build/dist/client/peer-host-scoped-client.js.map +1 -1
  142. package/data/build/dist/client/peer-host-workspace-tab.d.ts +8 -0
  143. package/data/build/dist/client/peer-host-workspace-tab.d.ts.map +1 -1
  144. package/data/build/dist/client/peer-host-workspace-tab.js +48 -28
  145. package/data/build/dist/client/peer-host-workspace-tab.js.map +1 -1
  146. package/data/build/dist/client/provider-icon-assets.js +4 -0
  147. package/data/build/dist/client/provider-icon-assets.js.map +1 -1
  148. package/data/build/dist/client/provider-icons.d.ts +8 -2
  149. package/data/build/dist/client/provider-icons.d.ts.map +1 -1
  150. package/data/build/dist/client/provider-icons.js +13 -4
  151. package/data/build/dist/client/provider-icons.js.map +1 -1
  152. package/data/build/dist/client/pwa-install-prompt.d.ts +4 -1
  153. package/data/build/dist/client/pwa-install-prompt.d.ts.map +1 -1
  154. package/data/build/dist/client/pwa-install-prompt.js +8 -7
  155. package/data/build/dist/client/pwa-install-prompt.js.map +1 -1
  156. package/data/build/dist/client/quick-phrase-layout.d.ts +11 -0
  157. package/data/build/dist/client/quick-phrase-layout.d.ts.map +1 -1
  158. package/data/build/dist/client/quick-phrase-layout.js +20 -0
  159. package/data/build/dist/client/quick-phrase-layout.js.map +1 -1
  160. package/data/build/dist/client/quick-phrase-slot.d.ts.map +1 -1
  161. package/data/build/dist/client/quick-phrase-slot.js +20 -8
  162. package/data/build/dist/client/quick-phrase-slot.js.map +1 -1
  163. package/data/build/dist/client/session-changed-files-view.d.ts +8 -1
  164. package/data/build/dist/client/session-changed-files-view.d.ts.map +1 -1
  165. package/data/build/dist/client/session-changed-files-view.js +71 -28
  166. package/data/build/dist/client/session-changed-files-view.js.map +1 -1
  167. package/data/build/dist/client/settings-anchor.d.ts +9 -3
  168. package/data/build/dist/client/settings-anchor.d.ts.map +1 -1
  169. package/data/build/dist/client/settings-anchor.js +8 -2
  170. package/data/build/dist/client/settings-anchor.js.map +1 -1
  171. package/data/build/dist/client/settings-section.js +3 -3
  172. package/data/build/dist/client/settings-section.js.map +1 -1
  173. package/data/build/dist/client/subscription-slot.d.ts +4 -1
  174. package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
  175. package/data/build/dist/client/subscription-slot.js +327 -51
  176. package/data/build/dist/client/subscription-slot.js.map +1 -1
  177. package/data/build/dist/client/terminal/model.d.ts +13 -2
  178. package/data/build/dist/client/terminal/model.d.ts.map +1 -1
  179. package/data/build/dist/client/terminal/model.js +27 -7
  180. package/data/build/dist/client/terminal/model.js.map +1 -1
  181. package/data/build/dist/client/terminal/ui.d.ts.map +1 -1
  182. package/data/build/dist/client/terminal/ui.js +3 -1
  183. package/data/build/dist/client/terminal/ui.js.map +1 -1
  184. package/data/build/dist/client/terminal/xterm-view.d.ts +4 -1
  185. package/data/build/dist/client/terminal/xterm-view.d.ts.map +1 -1
  186. package/data/build/dist/client/terminal/xterm-view.js +19 -17
  187. package/data/build/dist/client/terminal/xterm-view.js.map +1 -1
  188. package/data/build/dist/client/workspace-session-archive-dom.d.ts +3 -0
  189. package/data/build/dist/client/workspace-session-archive-dom.d.ts.map +1 -1
  190. package/data/build/dist/client/workspace-session-archive-dom.js +131 -45
  191. package/data/build/dist/client/workspace-session-archive-dom.js.map +1 -1
  192. package/data/build/dist/client/workspace-session-logo-dom.d.ts +3 -0
  193. package/data/build/dist/client/workspace-session-logo-dom.d.ts.map +1 -1
  194. package/data/build/dist/client/workspace-session-logo-dom.js +3 -1
  195. package/data/build/dist/client/workspace-session-logo-dom.js.map +1 -1
  196. package/data/build/dist/client/workspace-session-visibility-dom.d.ts +3 -0
  197. package/data/build/dist/client/workspace-session-visibility-dom.d.ts.map +1 -1
  198. package/data/build/dist/client/workspace-session-visibility-dom.js +46 -17
  199. package/data/build/dist/client/workspace-session-visibility-dom.js.map +1 -1
  200. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +10 -0
  201. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts.map +1 -1
  202. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +20 -0
  203. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js.map +1 -1
  204. package/data/build/dist/host/browser-text.d.ts +30 -0
  205. package/data/build/dist/host/browser-text.d.ts.map +1 -0
  206. package/data/build/dist/host/browser-text.js +105 -0
  207. package/data/build/dist/host/browser-text.js.map +1 -0
  208. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +28 -2
  209. package/data/build/dist/host/cli-adapters/claude-driver.d.ts.map +1 -1
  210. package/data/build/dist/host/cli-adapters/claude-driver.js +73 -3
  211. package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
  212. package/data/build/dist/host/cli-adapters/claude-model-options.d.ts.map +1 -1
  213. package/data/build/dist/host/cli-adapters/claude-model-options.js +22 -9
  214. package/data/build/dist/host/cli-adapters/claude-model-options.js.map +1 -1
  215. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +10 -0
  216. package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
  217. package/data/build/dist/host/cli-adapters/codex-driver.js +105 -5
  218. package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
  219. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
  220. package/data/build/dist/host/cli-adapters/command-code-driver.js +49 -7
  221. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  222. package/data/build/dist/host/cli-adapters/delegate-dispatch.d.ts +47 -0
  223. package/data/build/dist/host/cli-adapters/delegate-dispatch.d.ts.map +1 -0
  224. package/data/build/dist/host/cli-adapters/delegate-dispatch.js +158 -0
  225. package/data/build/dist/host/cli-adapters/delegate-dispatch.js.map +1 -0
  226. package/data/build/dist/host/cli-adapters/desktop-app-runtime.d.ts +32 -0
  227. package/data/build/dist/host/cli-adapters/desktop-app-runtime.d.ts.map +1 -0
  228. package/data/build/dist/host/cli-adapters/desktop-app-runtime.js +121 -0
  229. package/data/build/dist/host/cli-adapters/desktop-app-runtime.js.map +1 -0
  230. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  231. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +5 -4
  232. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  233. package/data/build/dist/host/cli-adapters/dsh-virtual-providers.d.ts +16 -0
  234. package/data/build/dist/host/cli-adapters/dsh-virtual-providers.d.ts.map +1 -0
  235. package/data/build/dist/host/cli-adapters/dsh-virtual-providers.js +73 -0
  236. package/data/build/dist/host/cli-adapters/dsh-virtual-providers.js.map +1 -0
  237. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  238. package/data/build/dist/host/cli-adapters/feature.js +196 -14
  239. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  240. package/data/build/dist/host/cli-adapters/gemini-driver.d.ts.map +1 -1
  241. package/data/build/dist/host/cli-adapters/gemini-driver.js +21 -5
  242. package/data/build/dist/host/cli-adapters/gemini-driver.js.map +1 -1
  243. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  244. package/data/build/dist/host/cli-adapters/grok-driver.js +24 -7
  245. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  246. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +22 -6
  247. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts.map +1 -1
  248. package/data/build/dist/host/cli-adapters/json-rpc-process.js +118 -21
  249. package/data/build/dist/host/cli-adapters/json-rpc-process.js.map +1 -1
  250. package/data/build/dist/host/cli-adapters/kimi-driver.d.ts.map +1 -1
  251. package/data/build/dist/host/cli-adapters/kimi-driver.js +25 -4
  252. package/data/build/dist/host/cli-adapters/kimi-driver.js.map +1 -1
  253. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +11 -2
  254. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts.map +1 -1
  255. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +15 -6
  256. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js.map +1 -1
  257. package/data/build/dist/host/cli-adapters/mcode-catalog.d.ts +23 -0
  258. package/data/build/dist/host/cli-adapters/mcode-catalog.d.ts.map +1 -0
  259. package/data/build/dist/host/cli-adapters/mcode-catalog.js +120 -0
  260. package/data/build/dist/host/cli-adapters/mcode-catalog.js.map +1 -0
  261. package/data/build/dist/host/cli-adapters/mcode-driver.d.ts +56 -0
  262. package/data/build/dist/host/cli-adapters/mcode-driver.d.ts.map +1 -0
  263. package/data/build/dist/host/cli-adapters/mcode-driver.js +544 -0
  264. package/data/build/dist/host/cli-adapters/mcode-driver.js.map +1 -0
  265. package/data/build/dist/host/cli-adapters/model-catalog.d.ts +30 -5
  266. package/data/build/dist/host/cli-adapters/model-catalog.d.ts.map +1 -1
  267. package/data/build/dist/host/cli-adapters/model-catalog.js +83 -8
  268. package/data/build/dist/host/cli-adapters/model-catalog.js.map +1 -1
  269. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.d.ts +51 -0
  270. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.d.ts.map +1 -0
  271. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js +193 -0
  272. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js.map +1 -0
  273. package/data/build/dist/host/cli-adapters/native-subagent-holder.d.ts +4 -0
  274. package/data/build/dist/host/cli-adapters/native-subagent-holder.d.ts.map +1 -0
  275. package/data/build/dist/host/cli-adapters/native-subagent-holder.js +4 -0
  276. package/data/build/dist/host/cli-adapters/native-subagent-holder.js.map +1 -0
  277. package/data/build/dist/host/cli-adapters/native-team-proxy.js +18 -15
  278. package/data/build/dist/host/cli-adapters/native-team-proxy.js.map +1 -1
  279. package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts +45 -0
  280. package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts.map +1 -0
  281. package/data/build/dist/host/cli-adapters/native-team-subagent.js +107 -0
  282. package/data/build/dist/host/cli-adapters/native-team-subagent.js.map +1 -0
  283. package/data/build/dist/host/cli-adapters/opencode-driver.js +13 -3
  284. package/data/build/dist/host/cli-adapters/opencode-driver.js.map +1 -1
  285. package/data/build/dist/host/cli-adapters/pi-driver.js +24 -7
  286. package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
  287. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +8 -1
  288. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts.map +1 -1
  289. package/data/build/dist/host/cli-adapters/provider-subscription.js +98 -2
  290. package/data/build/dist/host/cli-adapters/provider-subscription.js.map +1 -1
  291. package/data/build/dist/host/cli-adapters/registry-holder.d.ts +4 -0
  292. package/data/build/dist/host/cli-adapters/registry-holder.d.ts.map +1 -0
  293. package/data/build/dist/host/cli-adapters/registry-holder.js +9 -0
  294. package/data/build/dist/host/cli-adapters/registry-holder.js.map +1 -0
  295. package/data/build/dist/host/cli-adapters/registry.d.ts +13 -0
  296. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  297. package/data/build/dist/host/cli-adapters/registry.js +37 -0
  298. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  299. package/data/build/dist/host/cli-adapters/session-store.d.ts +6 -1
  300. package/data/build/dist/host/cli-adapters/session-store.d.ts.map +1 -1
  301. package/data/build/dist/host/cli-adapters/session-store.js +42 -4
  302. package/data/build/dist/host/cli-adapters/session-store.js.map +1 -1
  303. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +2 -0
  304. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts.map +1 -1
  305. package/data/build/dist/host/cli-adapters/standard-stream-driver.js +30 -4
  306. package/data/build/dist/host/cli-adapters/standard-stream-driver.js.map +1 -1
  307. package/data/build/dist/host/cli-adapters/subagent-tool.d.ts +5 -0
  308. package/data/build/dist/host/cli-adapters/subagent-tool.d.ts.map +1 -0
  309. package/data/build/dist/host/cli-adapters/subagent-tool.js +66 -0
  310. package/data/build/dist/host/cli-adapters/subagent-tool.js.map +1 -0
  311. package/data/build/dist/host/cli-adapters/zcode-driver.d.ts +57 -0
  312. package/data/build/dist/host/cli-adapters/zcode-driver.d.ts.map +1 -0
  313. package/data/build/dist/host/cli-adapters/zcode-driver.js +843 -0
  314. package/data/build/dist/host/cli-adapters/zcode-driver.js.map +1 -0
  315. package/data/build/dist/host/cli-adapters/zcode-subscription.d.ts +28 -0
  316. package/data/build/dist/host/cli-adapters/zcode-subscription.d.ts.map +1 -0
  317. package/data/build/dist/host/cli-adapters/zcode-subscription.js +212 -0
  318. package/data/build/dist/host/cli-adapters/zcode-subscription.js.map +1 -0
  319. package/data/build/dist/host/cli-bridge/bridge-holder.d.ts +27 -0
  320. package/data/build/dist/host/cli-bridge/bridge-holder.d.ts.map +1 -0
  321. package/data/build/dist/host/cli-bridge/bridge-holder.js +51 -0
  322. package/data/build/dist/host/cli-bridge/bridge-holder.js.map +1 -0
  323. package/data/build/dist/host/cli-bridge/bridge-server.d.ts +34 -0
  324. package/data/build/dist/host/cli-bridge/bridge-server.d.ts.map +1 -0
  325. package/data/build/dist/host/cli-bridge/bridge-server.js +135 -0
  326. package/data/build/dist/host/cli-bridge/bridge-server.js.map +1 -0
  327. package/data/build/dist/host/cli-bridge/command-code-mod.d.ts +25 -0
  328. package/data/build/dist/host/cli-bridge/command-code-mod.d.ts.map +1 -0
  329. package/data/build/dist/host/cli-bridge/command-code-mod.js +60 -0
  330. package/data/build/dist/host/cli-bridge/command-code-mod.js.map +1 -0
  331. package/data/build/dist/host/cli-bridge/dispatch.d.ts +19 -0
  332. package/data/build/dist/host/cli-bridge/dispatch.d.ts.map +1 -0
  333. package/data/build/dist/host/cli-bridge/dispatch.js +90 -0
  334. package/data/build/dist/host/cli-bridge/dispatch.js.map +1 -0
  335. package/data/build/dist/host/cli-bridge/injections.d.ts +28 -0
  336. package/data/build/dist/host/cli-bridge/injections.d.ts.map +1 -0
  337. package/data/build/dist/host/cli-bridge/injections.js +131 -0
  338. package/data/build/dist/host/cli-bridge/injections.js.map +1 -0
  339. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.d.ts +8 -0
  340. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.d.ts.map +1 -0
  341. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js +151 -0
  342. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js.map +1 -0
  343. package/data/build/dist/host/features/lan-access-dsh.d.ts.map +1 -1
  344. package/data/build/dist/host/features/lan-access-dsh.js +6 -2
  345. package/data/build/dist/host/features/lan-access-dsh.js.map +1 -1
  346. package/data/build/dist/host/features/peer-host.d.ts.map +1 -1
  347. package/data/build/dist/host/features/peer-host.js +2 -1
  348. package/data/build/dist/host/features/peer-host.js.map +1 -1
  349. package/data/build/dist/host/index.d.ts +4 -0
  350. package/data/build/dist/host/index.d.ts.map +1 -1
  351. package/data/build/dist/host/index.js +36 -0
  352. package/data/build/dist/host/index.js.map +1 -1
  353. package/data/build/dist/host/lan-access-dsh.d.ts +7 -1
  354. package/data/build/dist/host/lan-access-dsh.d.ts.map +1 -1
  355. package/data/build/dist/host/lan-access-dsh.js +95 -19
  356. package/data/build/dist/host/lan-access-dsh.js.map +1 -1
  357. package/data/build/dist/host/login-attempt-guard.d.ts +55 -0
  358. package/data/build/dist/host/login-attempt-guard.d.ts.map +1 -0
  359. package/data/build/dist/host/login-attempt-guard.js +201 -0
  360. package/data/build/dist/host/login-attempt-guard.js.map +1 -0
  361. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.d.ts +3 -0
  362. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.d.ts.map +1 -1
  363. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.js +2 -0
  364. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.js.map +1 -1
  365. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.d.ts +1 -0
  366. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.d.ts.map +1 -1
  367. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.js +1 -0
  368. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.js.map +1 -1
  369. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.d.ts +1 -1
  370. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.d.ts.map +1 -1
  371. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.js +3 -0
  372. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.js.map +1 -1
  373. package/data/build/dist/host/modules/peer-host/peer-host-native-transport.d.ts +8 -0
  374. package/data/build/dist/host/modules/peer-host/peer-host-native-transport.d.ts.map +1 -1
  375. package/data/build/dist/host/modules/peer-host/peer-host-native-transport.js +9 -0
  376. package/data/build/dist/host/modules/peer-host/peer-host-native-transport.js.map +1 -1
  377. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.d.ts +7 -0
  378. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.d.ts.map +1 -1
  379. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.js +31 -3
  380. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.js.map +1 -1
  381. package/data/build/dist/host/modules/pwa/pwa-assets.d.ts +6 -4
  382. package/data/build/dist/host/modules/pwa/pwa-assets.d.ts.map +1 -1
  383. package/data/build/dist/host/modules/pwa/pwa-assets.js +11 -9
  384. package/data/build/dist/host/modules/pwa/pwa-assets.js.map +1 -1
  385. package/data/build/dist/host/modules/pwa/pwa-session-notifications.d.ts +3 -0
  386. package/data/build/dist/host/modules/pwa/pwa-session-notifications.d.ts.map +1 -1
  387. package/data/build/dist/host/modules/pwa/pwa-session-notifications.js +6 -4
  388. package/data/build/dist/host/modules/pwa/pwa-session-notifications.js.map +1 -1
  389. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  390. package/data/build/dist/host/native-session-bridge.js +70 -52
  391. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  392. package/data/build/dist/host/rpc.js +4 -1
  393. package/data/build/dist/host/rpc.js.map +1 -1
  394. package/data/build/dist/host/settings.d.ts.map +1 -1
  395. package/data/build/dist/host/settings.js +3 -0
  396. package/data/build/dist/host/settings.js.map +1 -1
  397. package/data/build/dist/shared/contracts/cli-adapter.d.ts +5 -0
  398. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  399. package/data/build/dist/shared/contracts/config.d.ts +10 -0
  400. package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
  401. package/data/build/dist/shared/contracts/config.js +8 -0
  402. package/data/build/dist/shared/contracts/config.js.map +1 -1
  403. package/data/build/dist/shared/contracts/peer-host.d.ts +2 -0
  404. package/data/build/dist/shared/contracts/peer-host.d.ts.map +1 -1
  405. package/data/build/dist/shared/contracts/peer-host.js.map +1 -1
  406. package/data/build/dist/shared/contracts/subscription.d.ts +15 -0
  407. package/data/build/dist/shared/contracts/subscription.d.ts.map +1 -1
  408. package/data/build/dist/shared/contracts/subscription.js.map +1 -1
  409. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  410. package/data/build/dist/shared/contracts/version.d.ts.map +1 -1
  411. package/data/build/dist/shared/contracts/version.js +1 -1
  412. package/data/build/dist/shared/contracts/version.js.map +1 -1
  413. package/data/build/dist/shared/index.d.ts +1 -1
  414. package/data/build/dist/shared/index.d.ts.map +1 -1
  415. package/data/build/dist/shared/index.js.map +1 -1
  416. package/package.json +3 -1
  417. package/profile/README.md +2 -2
  418. package/profile/package.json +2 -2
  419. package/profile/version.json +1 -1
  420. package/version.json +1 -1
@@ -5,6 +5,8 @@ import { backdropPointerDownHandler, useDismissOnOutsidePointer } from './popup-
5
5
  import { debugWarn } from '../shared/debug.js';
6
6
  import { dshSettingsToastStyle, dshThemeColor } from './theme.js';
7
7
  import { gitPanelClass, installGitPanelStyles } from './git-panel-styles.js';
8
+ import { resolveCodingNsTranslator } from './locale.js';
9
+ import { notifyGitWorkspaceChanged } from './git-workspace-events.js';
8
10
  // 单列 Git 视图需要一个稳定的分段控件;这里保持 React 结构简单,避免引入额外依赖。
9
11
  function SegmentedControl({ id, value, options, onChange, label, disabled }) {
10
12
  const index = Math.max(0, options.findIndex((option) => option.value === value));
@@ -20,11 +22,12 @@ const INITIAL_HISTORY_LIMIT = 50;
20
22
  const HISTORY_PAGE_SIZE = 100;
21
23
  /** 兼容早期调用方使用的面板标识;实际注册已迁移到右侧 Sidebar。 */
22
24
  export const GIT_PANEL_ID = GIT_PROVIDER_ID;
23
- function gitOperationLabel(operation) {
24
- return operation === 'fetch' ? 'Fetch' : operation === 'pull' ? 'Pull' : operation === 'push' ? 'Push' : operation === 'undo' ? '撤销提交' : '刷新';
25
+ function gitOperationLabel(operation, t) {
26
+ return operation === 'fetch' ? t('git.opFetch') : operation === 'pull' ? t('git.opPull') : operation === 'push' ? t('git.opPush') : operation === 'undo' ? t('git.opUndo') : t('git.refresh');
25
27
  }
26
28
  /** 注册 DSH 右侧 Sidebar 的 Git 标签类型,数据按 Workspace 复用。 */
27
29
  export function registerGitManagementUi(ctx, services) {
30
+ const t = resolveCodingNsTranslator(services.locale);
28
31
  const disposers = [];
29
32
  disposers.push(installGitPanelStyles());
30
33
  const sidebarRight = ctx.sidebarRight;
@@ -34,15 +37,16 @@ export function registerGitManagementUi(ctx, services) {
34
37
  kind: GIT_KIND,
35
38
  multiple: false,
36
39
  priority: 'extension',
37
- title: () => 'Git',
38
- guide: [{ id: 'git', order: 40, title: () => 'Git', description: () => '查看改动、提交和版本历史', icon: GitPanelIcon }],
40
+ title: () => t('git.tabTitle'),
41
+ guide: [{ id: 'git', order: 40, title: () => t('git.tabTitle'), description: () => t('git.guideDescription'), icon: createGitPanelIcon(t) }],
39
42
  }));
40
43
  disposers.push(ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
41
44
  name: 'sidebar.right.pane.tab', key: GIT_PROVIDER_ID,
42
- inject: () => ({ rpc: services.rpc, remote: services.remote }),
45
+ inject: () => ({ rpc: services.rpc, remote: services.remote, t }),
43
46
  }, GitPanel)));
44
47
  disposers.push(ctx.slots.inject('sidebar.right.pane.tab.title', () => ctx.slots.register({
45
48
  name: 'sidebar.right.pane.tab.title', key: GIT_PROVIDER_ID,
49
+ inject: () => ({ t }),
46
50
  }, GitTabTitle)));
47
51
  disposers.push(ctx.slots.inject('shell.overlay', () => ctx.slots.register({
48
52
  name: 'shell.overlay', id: 'codingns4dsh-git-workspace-recovery', order: 990,
@@ -67,17 +71,20 @@ export function registerGitManagementUi(ctx, services) {
67
71
  function isDuplicateGitRegistration(error) {
68
72
  return error instanceof Error && /sidebarRight: (?:tab type id|tab kind) .* already registered/u.test(error.message);
69
73
  }
70
- function GitPanelIcon({ size = 16 }) {
71
- return createElement('span', {
72
- title: 'Git 仓库管理', 'aria-label': 'Git 仓库管理', style: { display: 'inline-flex', width: size, height: size, alignItems: 'center', justifyContent: 'center', color: dshThemeColor.labelSecondary, fontSize: Math.max(12, size - 2), fontWeight: 700 },
73
- }, '⑂');
74
+ function createGitPanelIcon(t) {
75
+ return function GitPanelIcon({ size = 16 }) {
76
+ return createElement('span', {
77
+ title: t('git.panelLabel'), 'aria-label': t('git.panelLabel'), style: { display: 'inline-flex', width: size, height: size, alignItems: 'center', justifyContent: 'center', color: dshThemeColor.labelSecondary, fontSize: Math.max(12, size - 2), fontWeight: 700 },
78
+ }, '⑂');
79
+ };
74
80
  }
75
- function GitTabTitle({ useTabInfo }) {
81
+ function GitTabTitle({ useTabInfo, t }) {
76
82
  useTabInfo();
77
- return createElement('span', { title: 'Git 仓库管理', 'aria-label': 'Git 仓库管理', style: tabTitleStyle }, 'Git');
83
+ return createElement('span', { title: t('git.panelLabel'), 'aria-label': t('git.panelLabel'), style: tabTitleStyle }, t('git.tabTitle'));
78
84
  }
79
85
  function GitPanel(props) {
80
86
  const sessionId = String(props.sessionId);
87
+ const t = props.t;
81
88
  const tabInfo = props.useTabInfo();
82
89
  const [workspaceId, setWorkspaceId] = useState();
83
90
  const [status, setStatus] = useState(null);
@@ -181,7 +188,7 @@ function GitPanel(props) {
181
188
  if (disposed)
182
189
  return;
183
190
  if (resolvedWorkspaceId === undefined) {
184
- notify('error', '当前没有可用的工作区');
191
+ notify('error', t('git.noWorkspace'));
185
192
  return;
186
193
  }
187
194
  rememberGitWorkspaceSession(sessionId, resolvedWorkspaceId);
@@ -210,13 +217,13 @@ function GitPanel(props) {
210
217
  }, [sessionId, tabInfo.tab.signal]);
211
218
  const run = async (action, payload, onSuccess, operation) => {
212
219
  if (workspaceId === undefined) {
213
- notify('error', '当前没有可用的工作区');
220
+ notify('error', t('git.noWorkspace'));
214
221
  return;
215
222
  }
216
223
  setBusy(true);
217
224
  if (operation !== undefined) {
218
225
  setActiveOperation(operation);
219
- setToast({ kind: 'info', message: `正在${gitOperationLabel(operation)}…` });
226
+ setToast({ kind: 'info', message: t('git.operationRunning', { operation: gitOperationLabel(operation, t) }) });
220
227
  }
221
228
  else {
222
229
  setToast(null);
@@ -227,6 +234,8 @@ function GitPanel(props) {
227
234
  historyExpanded.current = false;
228
235
  try {
229
236
  const value = await call(props.rpc, action, { workspaceId: targetWorkspaceId, ...payload });
237
+ if (action !== 'git/status')
238
+ notifyGitWorkspaceChanged(targetWorkspaceId);
230
239
  onSuccess?.(value);
231
240
  const nextStatus = await call(props.rpc, 'git/status', { workspaceId: targetWorkspaceId });
232
241
  setStatus(nextStatus);
@@ -249,7 +258,7 @@ function GitPanel(props) {
249
258
  setBranches(null);
250
259
  writeCache(targetWorkspaceId, { status: nextStatus, history: [], historyTotalCount: 0, branches: null });
251
260
  }
252
- notify('success', operation === undefined ? '操作已完成' : `${gitOperationLabel(operation)}已完成`);
261
+ notify('success', operation === undefined ? t('git.operationCompleted') : t('git.operationDone', { operation: gitOperationLabel(operation, t) }));
253
262
  }
254
263
  catch (error) {
255
264
  notify('error', error instanceof Error ? error.message : String(error));
@@ -264,22 +273,22 @@ function GitPanel(props) {
264
273
  const commit = () => {
265
274
  const value = subject.trim();
266
275
  if (!value) {
267
- notify('error', '请输入提交说明');
276
+ notify('error', t('git.commitMessageRequired'));
268
277
  return;
269
278
  }
270
279
  void run('git/commit', { subject: value }, () => setSubject(''));
271
280
  };
272
281
  const copyCommitHash = (commitHash) => {
273
- void copyText(commitHash).then((copied) => notify(copied ? 'success' : 'error', copied ? 'Git 版本号已复制' : '当前环境不支持复制'));
282
+ void copyText(commitHash).then((copied) => notify(copied ? 'success' : 'error', copied ? t('git.commitHashCopied') : t('git.copyUnsupported')));
274
283
  };
275
284
  const copyCommitMessage = (value) => {
276
- void copyText(value).then((copied) => notify(copied ? 'success' : 'error', copied ? '提交信息已复制' : '当前环境不支持复制'));
285
+ void copyText(value).then((copied) => notify(copied ? 'success' : 'error', copied ? t('git.commitMessageCopied') : t('git.copyUnsupported')));
277
286
  };
278
287
  const openCommitDiff = (commitHash) => {
279
288
  if (workspaceId === undefined)
280
289
  return;
281
290
  setBusy(true);
282
- notify('info', '正在读取提交 Diff…');
291
+ notify('info', t('git.readingCommitDiff'));
283
292
  void call(props.rpc, 'git/commit-diff', { workspaceId, commitHash }).then((value) => {
284
293
  setDiffView(value);
285
294
  setToast(null);
@@ -289,7 +298,7 @@ function GitPanel(props) {
289
298
  if (workspaceId === undefined)
290
299
  return;
291
300
  setBusy(true);
292
- notify('info', '正在读取文件 Diff…');
301
+ notify('info', t('git.readingFileDiff'));
293
302
  void call(props.rpc, 'git/diff', { workspaceId, path, staged }).then((value) => {
294
303
  setFileDiff({ path, staged, diff: value });
295
304
  setToast(null);
@@ -320,55 +329,54 @@ function GitPanel(props) {
320
329
  return createElement('section', { style: panelStyle, 'data-git-management-panel': 'true' },
321
330
  // 面板标题已由 Sidebar 标签页渲染,这里不再重复;只保留视图切换与操作菜单。
322
331
  createElement('header', { style: headerStyle }, singleColumn ? createElement('div', { style: columnSwitchStyle }, createElement((SegmentedControl), {
323
- id: 'codingns4dsh-git-view', value: activeColumn, onChange: setActiveColumn, label: '切换文件与版本视图',
332
+ id: 'codingns4dsh-git-view', value: activeColumn, onChange: setActiveColumn, label: t('git.viewSwitcherLabel'),
324
333
  options: [
325
- { value: 'files', label: '切换文件', title: '切换文件' },
326
- { value: 'history', label: '切换版本', title: '切换版本' },
334
+ { value: 'files', label: t('git.switchToFiles'), title: t('git.switchToFiles') },
335
+ { value: 'history', label: t('git.switchToHistory'), title: t('git.switchToHistory') },
327
336
  ],
328
- })) : null, createElement('div', { style: headerActionsStyle }, createElement(GitOperationsMenu, { busy, activeOperation, hasRemote: Boolean(status?.snapshot.hasRemote || branches?.remote.length), canUndo: history.length > 0, hasMoreVersions: history.length < historyTotalCount, stagedCount: staged.length, unstagedCount: unstaged.length, onStageAll: stageAll, onDiscardAll: discardAll, onLoadMore: loadMoreHistory, onOperation: runGitOperation }))), toast === null ? null : createElement('div', { role: toast.kind === 'error' ? 'alert' : 'status', 'aria-live': 'polite', style: { ...dshSettingsToastStyle, position: 'absolute', top: 8, right: 'auto', left: '50%', transform: 'translateX(-50%)', width: 'min(300px, calc(100% - 24px))', pointerEvents: 'none', borderColor: toast.kind === 'error' ? dshThemeColor.error : toast.kind === 'success' ? dshThemeColor.success : dshThemeColor.border } }, toast.message), status === null ? createElement('div', { style: emptyStyle }, '正在读取 Git 状态…') : null, status !== null && status.snapshot.enabled === false ? createElement('section', { style: sectionStyle }, createElement('strong', undefined, '当前目录还没有 Git 仓库'), createElement('div', { style: mutedStyle }, '初始化后即可查看改动、提交和版本历史。'), createElement('button', { type: 'button', disabled: busy, onClick: () => void run('git/init', {}), className: `${gitPanelClass.button} ${gitPanelClass.buttonPrimary}`, style: primaryButtonStyle }, '初始化 Git')) : null, status !== null ? createElement('div', { style: summaryStyle }, `${staged.length} 个已暂存 · ${unstaged.length} 个未暂存 · ${historyTotalCount} 条提交(${historyScope === 'all' ? '全部分支' : '当前分支'})`) : null, diffView !== null ? createElement(DiffViewer, { diff: diffView, onClose: () => setDiffView(null) }) : null, fileDiff !== null ? createElement(FileDiffViewer, { path: fileDiff.path, staged: fileDiff.staged, diff: fileDiff.diff, onClose: () => setFileDiff(null) }) : null, status !== null && status.snapshot.enabled !== false ? createElement('div', { ref: contentGridRef, style: contentGridStyle }, singleColumn && activeColumn !== 'files' ? null : createElement('div', { style: columnStyle }, createElement('section', { style: commitSectionStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', undefined, '提交更改'), createElement('span', { style: mutedStyle }, staged.length === 0 ? '暂存区为空' : `${staged.length} 个已暂存`)), createElement('div', { style: commitEditorRowStyle }, createElement('textarea', { value: subject, disabled: busy || workspaceId === undefined, className: gitPanelClass.field, onChange: (event) => setSubject(event.currentTarget.value), onKeyDown: (event) => { if (event.key === 'Enter')
329
- event.preventDefault(); }, placeholder: '在这里输入提交信息', rows: 1, style: commitSubjectStyle }), createElement('button', { type: 'button', disabled: busy || workspaceId === undefined, onClick: () => notify('info', '生成提交信息功能暂未开放'), className: `${gitPanelClass.button} ${gitPanelClass.field}`, style: draftButtonStyle, title: '生成提交信息', 'aria-label': '生成提交信息' }, '✦')), createElement('div', { style: commitActionsStyle }, createElement('button', { type: 'button', disabled: busy || workspaceId === undefined, onClick: () => void run('git/status', {}, (value) => setStatus(value)), className: `${gitPanelClass.button} ${gitPanelClass.field}`, style: refreshActionStyle }, '刷新'), createElement('button', { type: 'button', disabled: busy || workspaceId === undefined || staged.length === 0 || subject.trim().length === 0, onClick: commit, className: `${gitPanelClass.button} ${gitPanelClass.buttonPrimary}`, style: submitActionStyle }, '提交'))), staged.length > 0 ? createElement(ChangeSection, { title: '暂存文件', items: staged, busy, onOpenDiff: openFileDiff, onAction: (action, path) => void run(`git/${action}`, { targets: [path] }), onBatchAction: (action, paths) => void run(`git/${action}`, { targets: paths }), onBulkAction: () => void run('git/unstage', { targets: staged.map((item) => item.path) }) }) : null, unstaged.length > 0 ? createElement(ChangeSection, { title: '未提交文件', items: unstaged, busy, onOpenDiff: openFileDiff, onAction: (action, path) => void run(`git/${action}`, { targets: [path] }), onBatchAction: (action, paths) => void run(`git/${action}`, { targets: paths }), onBulkAction: () => void run('git/stage', { targets: unstaged.map((item) => item.path) }) }) : null), singleColumn && activeColumn !== 'history' ? null : createElement('div', { style: columnStyle }, createElement(HistorySection, { history, totalCount: historyTotalCount, hasMore: history.length < historyTotalCount, loadingMore: historyLoadingMore, onLoadMore: loadMoreHistory, branches, busy, scope: historyScope, hasRemote: Boolean(status?.snapshot.hasRemote || branches?.remote.length), onScopeChange: setHistoryScope, onSwitch: (branchName) => void run('git/switch', { branchName, create: false }, (value) => setBranches(normalizeBranchSnapshot(value))), onCopy: copyCommitHash, onCopyMessage: copyCommitMessage, onViewDiff: openCommitDiff, onUndo: () => runGitOperation('undo') }))) : null);
337
+ })) : null, createElement('div', { style: headerActionsStyle }, createElement(GitOperationsMenu, { busy, activeOperation, hasRemote: Boolean(status?.snapshot.hasRemote || branches?.remote.length), canUndo: history.length > 0, hasMoreVersions: history.length < historyTotalCount, stagedCount: staged.length, unstagedCount: unstaged.length, onStageAll: stageAll, onDiscardAll: discardAll, onLoadMore: loadMoreHistory, onOperation: runGitOperation, t }))), toast === null ? null : createElement('div', { role: toast.kind === 'error' ? 'alert' : 'status', 'aria-live': 'polite', style: { ...dshSettingsToastStyle, position: 'absolute', top: 8, right: 'auto', left: '50%', transform: 'translateX(-50%)', width: 'min(300px, calc(100% - 24px))', pointerEvents: 'none', borderColor: toast.kind === 'error' ? dshThemeColor.error : toast.kind === 'success' ? dshThemeColor.success : dshThemeColor.border } }, toast.message), status === null ? createElement('div', { style: emptyStyle }, t('git.readingStatus')) : null, status !== null && status.snapshot.enabled === false ? createElement('section', { style: sectionStyle }, createElement('strong', undefined, t('git.noRepository')), createElement('div', { style: mutedStyle }, t('git.initHint')), createElement('button', { type: 'button', disabled: busy, onClick: () => void run('git/init', {}), className: `${gitPanelClass.button} ${gitPanelClass.buttonPrimary}`, style: primaryButtonStyle }, t('git.init'))) : null, status !== null ? createElement('div', { style: summaryStyle }, t('git.summary', { staged: staged.length, unstaged: unstaged.length, total: historyTotalCount, scope: historyScope === 'all' ? t('git.allBranches') : t('git.currentBranch') })) : null, diffView !== null ? createElement(DiffViewer, { diff: diffView, onClose: () => setDiffView(null), t }) : null, fileDiff !== null ? createElement(FileDiffViewer, { path: fileDiff.path, staged: fileDiff.staged, diff: fileDiff.diff, onClose: () => setFileDiff(null), t }) : null, status !== null && status.snapshot.enabled !== false ? createElement('div', { ref: contentGridRef, style: contentGridStyle }, singleColumn && activeColumn !== 'files' ? null : createElement('div', { style: columnStyle }, createElement('section', { style: commitSectionStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', undefined, t('git.commitChanges')), createElement('span', { style: mutedStyle }, staged.length === 0 ? t('git.stagingEmpty') : t('git.stagedCount', { count: staged.length }))), createElement('div', { style: commitEditorRowStyle }, createElement('textarea', { value: subject, disabled: busy || workspaceId === undefined, className: gitPanelClass.field, onChange: (event) => setSubject(event.currentTarget.value), onKeyDown: (event) => { if (event.key === 'Enter')
338
+ event.preventDefault(); }, placeholder: t('git.commitPlaceholder'), rows: 1, style: commitSubjectStyle }), createElement('button', { type: 'button', disabled: busy || workspaceId === undefined, onClick: () => notify('info', t('git.draftUnavailable')), className: `${gitPanelClass.button} ${gitPanelClass.field}`, style: draftButtonStyle, title: t('git.draftMessage'), 'aria-label': t('git.draftMessage') }, '✦')), createElement('div', { style: commitActionsStyle }, createElement('button', { type: 'button', disabled: busy || workspaceId === undefined, onClick: () => void run('git/status', {}, (value) => setStatus(value)), className: `${gitPanelClass.button} ${gitPanelClass.field}`, style: refreshActionStyle }, t('git.refresh')), createElement('button', { type: 'button', disabled: busy || workspaceId === undefined || staged.length === 0 || subject.trim().length === 0, onClick: commit, className: `${gitPanelClass.button} ${gitPanelClass.buttonPrimary}`, style: submitActionStyle }, t('git.commit')))), staged.length > 0 ? createElement(ChangeSection, { title: t('git.stagedFiles'), staged: true, items: staged, busy, onOpenDiff: openFileDiff, onAction: (action, path) => void run(`git/${action}`, { targets: [path] }), onBatchAction: (action, paths) => void run(`git/${action}`, { targets: paths }), onBulkAction: () => void run('git/unstage', { targets: staged.map((item) => item.path) }), t }) : null, unstaged.length > 0 ? createElement(ChangeSection, { title: t('git.unstagedFiles'), staged: false, items: unstaged, busy, onOpenDiff: openFileDiff, onAction: (action, path) => void run(`git/${action}`, { targets: [path] }), onBatchAction: (action, paths) => void run(`git/${action}`, { targets: paths }), onBulkAction: () => void run('git/stage', { targets: unstaged.map((item) => item.path) }), t }) : null), singleColumn && activeColumn !== 'history' ? null : createElement('div', { style: columnStyle }, createElement(HistorySection, { history, totalCount: historyTotalCount, hasMore: history.length < historyTotalCount, loadingMore: historyLoadingMore, onLoadMore: loadMoreHistory, branches, busy, scope: historyScope, hasRemote: Boolean(status?.snapshot.hasRemote || branches?.remote.length), onScopeChange: setHistoryScope, onSwitch: (branchName) => void run('git/switch', { branchName, create: false }, (value) => setBranches(normalizeBranchSnapshot(value))), onCopy: copyCommitHash, onCopyMessage: copyCommitMessage, onViewDiff: openCommitDiff, onUndo: () => runGitOperation('undo'), t }))) : null);
330
339
  }
331
- function ChangeSection({ title, items, busy, onOpenDiff, onAction, onBatchAction, onBulkAction }) {
340
+ function ChangeSection({ title, staged, items, busy, onOpenDiff, onAction, onBatchAction, onBulkAction, t }) {
332
341
  const [hoveredPath, setHoveredPath] = useState(null);
333
342
  const nodes = buildChangeTree(items);
334
- const staged = title === '暂存文件';
335
343
  const renderNode = (node, depth) => {
336
344
  if (node.kind === 'directory') {
337
345
  const directoryKey = `dir:${node.path}`;
338
346
  const directoryTargets = collectTreeTargets(node);
339
347
  const isHovered = hoveredPath === directoryKey;
340
- return createElement('details', { key: `dir:${node.path}`, open: true, style: treeDirectoryStyle }, createElement('summary', { className: gitPanelClass.row, style: { ...treeRowStyle, paddingLeft: 8 + depth * 14 }, onMouseEnter: () => setHoveredPath(directoryKey), onMouseLeave: () => setHoveredPath(null) }, createElement('span', { style: treeChevronStyle }, '⌄'), createElement('span', { style: folderIconStyle }, '▰'), createElement('span', { style: fileNameStyle, title: node.path }, node.name), createElement('span', { style: mutedStyle }, countTreeFiles(node)), isHovered ? createElement('div', { style: rowActionsStyle }, createElement('button', { type: 'button', disabled: busy, onClick: (event) => { event.preventDefault(); event.stopPropagation(); onBatchAction(staged ? 'unstage' : 'stage', directoryTargets); }, className: gitPanelClass.action, style: iconActionStyle, title: staged ? '撤销目录暂存' : '将目录添加到暂存区', 'aria-label': staged ? '撤销目录暂存' : '将目录添加到暂存区' }, staged ? '↶' : '+'), !staged ? createElement('button', { type: 'button', disabled: busy, onClick: (event) => { event.preventDefault(); event.stopPropagation(); onBatchAction('discard', directoryTargets); }, className: `${gitPanelClass.action} ${gitPanelClass.actionDanger}`, style: iconActionStyle, title: '撤销目录变更', 'aria-label': '撤销目录变更' }, '×') : null) : null), createElement('div', undefined, ...node.children.map((child) => renderNode(child, depth + 1))));
348
+ return createElement('details', { key: `dir:${node.path}`, open: true, style: treeDirectoryStyle }, createElement('summary', { className: gitPanelClass.row, style: { ...treeRowStyle, paddingLeft: 8 + depth * 14 }, onMouseEnter: () => setHoveredPath(directoryKey), onMouseLeave: () => setHoveredPath(null) }, createElement('span', { style: treeChevronStyle }, '⌄'), createElement('span', { style: folderIconStyle }, '▰'), createElement('span', { style: fileNameStyle, title: node.path }, node.name), createElement('span', { style: mutedStyle }, countTreeFiles(node)), isHovered ? createElement('div', { style: rowActionsStyle }, createElement('button', { type: 'button', disabled: busy, onClick: (event) => { event.preventDefault(); event.stopPropagation(); onBatchAction(staged ? 'unstage' : 'stage', directoryTargets); }, className: gitPanelClass.action, style: iconActionStyle, title: staged ? t('git.unstageDirectory') : t('git.stageDirectory'), 'aria-label': staged ? t('git.unstageDirectory') : t('git.stageDirectory') }, staged ? '↶' : '+'), !staged ? createElement('button', { type: 'button', disabled: busy, onClick: (event) => { event.preventDefault(); event.stopPropagation(); onBatchAction('discard', directoryTargets); }, className: `${gitPanelClass.action} ${gitPanelClass.actionDanger}`, style: iconActionStyle, title: t('git.discardDirectory'), 'aria-label': t('git.discardDirectory') }, '×') : null) : null), createElement('div', undefined, ...node.children.map((child) => renderNode(child, depth + 1))));
341
349
  }
342
350
  const isHovered = hoveredPath === node.path;
343
- return createElement('div', { key: `file:${node.path}`, className: gitPanelClass.row, style: { ...treeRowStyle, paddingLeft: 28 + depth * 14 }, onMouseEnter: () => setHoveredPath(node.path), onMouseLeave: () => setHoveredPath(null), onDoubleClick: () => onOpenDiff(node.path, staged) }, createElement('span', { style: fileIconStyle }, fileIcon(node.name)), createElement('span', { title: node.path, style: fileNameStyle }, node.name), createElement('span', { style: fileStatusStyle }, changeStatus(node.item, staged)), isHovered ? createElement('div', { style: rowActionsStyle }, createElement('button', { type: 'button', disabled: busy, onClick: () => onAction(staged ? 'unstage' : 'stage', node.path), className: gitPanelClass.action, style: iconActionStyle, title: staged ? '撤销暂存' : '添加到暂存区', 'aria-label': staged ? '撤销暂存' : '添加到暂存区' }, staged ? '↶' : '+'), !staged ? createElement('button', { type: 'button', disabled: busy, onClick: () => onAction('discard', node.path), className: `${gitPanelClass.action} ${gitPanelClass.actionDanger}`, style: iconActionStyle, title: '撤销变更', 'aria-label': '撤销变更' }, '×') : null) : null);
351
+ return createElement('div', { key: `file:${node.path}`, className: gitPanelClass.row, style: { ...treeRowStyle, paddingLeft: 28 + depth * 14 }, onMouseEnter: () => setHoveredPath(node.path), onMouseLeave: () => setHoveredPath(null), onDoubleClick: () => onOpenDiff(node.path, staged) }, createElement('span', { style: fileIconStyle }, fileIcon(node.name)), createElement('span', { title: node.path, style: fileNameStyle }, node.name), createElement('span', { style: fileStatusStyle }, changeStatus(node.item, staged)), isHovered ? createElement('div', { style: rowActionsStyle }, createElement('button', { type: 'button', disabled: busy, onClick: () => onAction(staged ? 'unstage' : 'stage', node.path), className: gitPanelClass.action, style: iconActionStyle, title: staged ? t('git.unstageFile') : t('git.stageFile'), 'aria-label': staged ? t('git.unstageFile') : t('git.stageFile') }, staged ? '↶' : '+'), !staged ? createElement('button', { type: 'button', disabled: busy, onClick: () => onAction('discard', node.path), className: `${gitPanelClass.action} ${gitPanelClass.actionDanger}`, style: iconActionStyle, title: t('git.discardFile'), 'aria-label': t('git.discardFile') }, '×') : null) : null);
344
352
  };
345
- return createElement('section', { style: sectionStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', undefined, `${title} (${items.length})`), createElement('button', { type: 'button', disabled: busy, onClick: onBulkAction, className: gitPanelClass.action, style: iconActionStyle, title: staged ? '取消全部暂存' : '全部添加到暂存区', 'aria-label': staged ? '取消全部暂存' : '全部添加到暂存区' }, staged ? '↶' : '+')), createElement('div', { style: treeStyle }, ...nodes.map((node) => renderNode(node, 0))));
353
+ return createElement('section', { style: sectionStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', undefined, `${title} (${items.length})`), createElement('button', { type: 'button', disabled: busy, onClick: onBulkAction, className: gitPanelClass.action, style: iconActionStyle, title: staged ? t('git.unstageAll') : t('git.addAllToStaging'), 'aria-label': staged ? t('git.unstageAll') : t('git.addAllToStaging') }, staged ? '↶' : '+')), createElement('div', { style: treeStyle }, ...nodes.map((node) => renderNode(node, 0))));
346
354
  }
347
- function GitOperationsMenu({ busy, activeOperation, hasRemote, canUndo, hasMoreVersions, stagedCount, unstagedCount, onStageAll, onDiscardAll, onLoadMore, onOperation }) {
355
+ function GitOperationsMenu({ busy, activeOperation, hasRemote, canUndo, hasMoreVersions, stagedCount, unstagedCount, onStageAll, onDiscardAll, onLoadMore, onOperation, t }) {
348
356
  const [open, setOpen] = useState(false);
349
357
  const rootRef = useRef(null);
350
358
  useDismissOnOutsidePointer(rootRef, open, () => setOpen(false));
351
359
  // 菜单项统一在点击后收起;关闭动作与具体操作解耦,避免每个按钮各写一次。
352
360
  const run = (action) => () => { setOpen(false); action(); };
353
- const operationText = activeOperation === null ? null : `${gitOperationLabel(activeOperation)}进行中…`;
361
+ const operationText = activeOperation === null ? null : t('git.operationInProgress', { operation: gitOperationLabel(activeOperation, t) });
354
362
  const operationBadge = operationText === null ? null : createElement('span', { role: 'status', 'aria-live': 'polite', style: operationStatusStyle }, createElement('span', { className: gitPanelClass.progress, 'aria-hidden': 'true' }, '⟳'), operationText);
355
- return createElement('div', { ref: rootRef, style: menuStyle }, operationBadge, createElement('button', { type: 'button', disabled: busy, className: gitPanelClass.menuTrigger, style: iconActionStyle, title: 'Git 操作菜单', 'aria-label': 'Git 操作菜单', 'aria-haspopup': 'menu', 'aria-expanded': open, onClick: () => setOpen((value) => !value) }, '⋯'), open && createElement('div', { role: 'menu', 'aria-label': 'Git 操作菜单', className: gitPanelClass.menu, style: menuPopupStyle }, createElement('button', { type: 'button', role: 'menuitem', disabled: busy || unstagedCount === 0, onClick: run(onStageAll), className: gitPanelClass.menuItem, style: menuItemStyle }, '暂存全部'), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || stagedCount + unstagedCount === 0, onClick: run(onDiscardAll), className: `${gitPanelClass.menuItem} ${gitPanelClass.menuItemDanger}`, style: menuItemStyle }, '放弃全部改动'), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasRemote, onClick: run(() => onOperation('fetch')), className: gitPanelClass.menuItem, style: menuItemStyle }, 'Fetch'), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasRemote, 'aria-busy': activeOperation === 'pull', onClick: run(() => onOperation('pull')), className: gitPanelClass.menuItem, style: menuItemStyle }, activeOperation === 'pull' ? '⟳ Pull 进行中…' : 'Pull'),
363
+ return createElement('div', { ref: rootRef, style: menuStyle }, operationBadge, createElement('button', { type: 'button', disabled: busy, className: gitPanelClass.menuTrigger, style: iconActionStyle, title: t('git.operationsMenu'), 'aria-label': t('git.operationsMenu'), 'aria-haspopup': 'menu', 'aria-expanded': open, onClick: () => setOpen((value) => !value) }, '⋯'), open && createElement('div', { role: 'menu', 'aria-label': t('git.operationsMenu'), className: gitPanelClass.menu, style: menuPopupStyle }, createElement('button', { type: 'button', role: 'menuitem', disabled: busy || unstagedCount === 0, onClick: run(onStageAll), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.stageAll')), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || stagedCount + unstagedCount === 0, onClick: run(onDiscardAll), className: `${gitPanelClass.menuItem} ${gitPanelClass.menuItemDanger}`, style: menuItemStyle }, t('git.discardAllChanges')), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasRemote, onClick: run(() => onOperation('fetch')), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.opFetch')), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasRemote, 'aria-busy': activeOperation === 'pull', onClick: run(() => onOperation('pull')), className: gitPanelClass.menuItem, style: menuItemStyle }, activeOperation === 'pull' ? t('git.pullRunning') : t('git.opPull')),
356
364
  // 工作区有未提交改动不影响已提交对象的 Push;Git Push 只发送提交记录。
357
- createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasRemote, 'aria-busy': activeOperation === 'push', onClick: run(() => onOperation('push')), className: gitPanelClass.menuItem, style: menuItemStyle }, activeOperation === 'push' ? '⟳ Push 进行中…' : 'Push'), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasMoreVersions, onClick: run(onLoadMore), className: gitPanelClass.menuItem, style: menuItemStyle, title: '查看所有版本' }, '查看更多版本(每次 100 条)'), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !canUndo, onClick: run(() => onOperation('undo')), className: gitPanelClass.menuItem, style: menuItemStyle }, '撤销上次提交'), createElement('button', { type: 'button', role: 'menuitem', disabled: busy, onClick: run(() => onOperation('refresh')), className: gitPanelClass.menuItem, style: menuItemStyle }, '刷新')));
365
+ createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasRemote, 'aria-busy': activeOperation === 'push', onClick: run(() => onOperation('push')), className: gitPanelClass.menuItem, style: menuItemStyle }, activeOperation === 'push' ? t('git.pushRunning') : t('git.opPush')), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !hasMoreVersions, onClick: run(onLoadMore), className: gitPanelClass.menuItem, style: menuItemStyle, title: t('git.viewAllVersions') }, t('git.loadMoreVersions')), createElement('button', { type: 'button', role: 'menuitem', disabled: busy || !canUndo, onClick: run(() => onOperation('undo')), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.undoLastCommit')), createElement('button', { type: 'button', role: 'menuitem', disabled: busy, onClick: run(() => onOperation('refresh')), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.refresh'))));
358
366
  }
359
- function DiffViewer({ diff, onClose }) {
367
+ function DiffViewer({ diff, onClose, t }) {
360
368
  const providedFiles = diff.files ?? [];
361
369
  const files = providedFiles.length > 0 ? providedFiles : parseDiffFiles(diff.content);
362
- return createElement('div', { style: diffOverlayStyle, onPointerDown: backdropPointerDownHandler(onClose) }, createElement('section', { role: 'dialog', 'aria-modal': true, 'aria-label': '提交 Diff', style: diffStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', undefined, `提交 Diff · ${diff.commitHash.slice(0, 8)}`), createElement('button', { type: 'button', onClick: onClose, className: gitPanelClass.action, style: iconActionStyle, title: '关闭 Diff', 'aria-label': '关闭 Diff' }, '×')), createElement('div', { style: diffBodyStyle }, createElement('section', { style: diffFilesSectionStyle }, createElement('div', { style: diffSectionHeaderStyle }, createElement('strong', undefined, '变更文件'), createElement('span', { style: diffCountStyle }, String(files.length))), files.length === 0 ? createElement('div', { style: diffEmptyStyle }, '没有检测到文件变更。') : createElement('div', { style: diffFileListStyle }, ...files.map((file) => createElement('div', { key: `${file.status}:${file.oldPath ?? ''}:${file.path}`, style: diffFileRowStyle }, createElement('span', { style: diffFileStatusStyle, 'data-status': file.status }, diffFileStatusLabel(file.status)), createElement('div', { style: diffFileNameStyle }, createElement('strong', undefined, file.path), file.oldPath ? createElement('span', { style: diffFileOldPathStyle }, `原路径:${file.oldPath}`) : null), file.binary ? createElement('span', { style: diffBinaryStyle }, '二进制') : null)))), createElement('section', { style: diffDiffSectionStyle }, createElement('div', { style: diffSectionHeaderStyle }, createElement('strong', undefined, 'Diff'), diff.truncated ? createElement('span', { style: diffTruncatedStyle }, '内容已截断') : null), createElement(DiffLines, { content: diff.content })))));
370
+ return createElement('div', { style: diffOverlayStyle, onPointerDown: backdropPointerDownHandler(onClose) }, createElement('section', { role: 'dialog', 'aria-modal': true, 'aria-label': t('git.commitDiff'), style: diffStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', undefined, t('git.commitDiffTitle', { hash: diff.commitHash.slice(0, 8) })), createElement('button', { type: 'button', onClick: onClose, className: gitPanelClass.action, style: iconActionStyle, title: t('git.closeDiff'), 'aria-label': t('git.closeDiff') }, '×')), createElement('div', { style: diffBodyStyle }, createElement('section', { style: diffFilesSectionStyle }, createElement('div', { style: diffSectionHeaderStyle }, createElement('strong', undefined, t('git.changedFiles')), createElement('span', { style: diffCountStyle }, String(files.length))), files.length === 0 ? createElement('div', { style: diffEmptyStyle }, t('git.noFileChanges')) : createElement('div', { style: diffFileListStyle }, ...files.map((file) => createElement('div', { key: `${file.status}:${file.oldPath ?? ''}:${file.path}`, style: diffFileRowStyle }, createElement('span', { style: diffFileStatusStyle, 'data-status': file.status }, diffFileStatusLabel(file.status, t)), createElement('div', { style: diffFileNameStyle }, createElement('strong', undefined, file.path), file.oldPath ? createElement('span', { style: diffFileOldPathStyle }, t('git.originalPath', { path: file.oldPath })) : null), file.binary ? createElement('span', { style: diffBinaryStyle }, t('git.binary')) : null)))), createElement('section', { style: diffDiffSectionStyle }, createElement('div', { style: diffSectionHeaderStyle }, createElement('strong', undefined, 'Diff'), diff.truncated ? createElement('span', { style: diffTruncatedStyle }, t('git.truncated')) : null), createElement(DiffLines, { content: diff.content, t })))));
363
371
  }
364
- function DiffLines({ content }) {
372
+ function DiffLines({ content, t }) {
365
373
  const lines = parseDiffLines(content);
366
374
  if (lines.length === 0)
367
- return createElement('div', { style: diffEmptyStyle }, '当前没有可显示的文本差异。');
375
+ return createElement('div', { style: diffEmptyStyle }, t('git.noTextDiff'));
368
376
  return createElement('div', { style: diffLinesStyle }, ...lines.map((line, index) => createElement('div', { key: `${index}:${line.kind}:${line.text}`, style: diffLineStyle(line.kind) }, createElement('span', { style: diffLineNumberStyle }, line.oldLineNo === null ? '' : String(line.oldLineNo)), createElement('span', { style: diffLineNumberStyle }, line.newLineNo === null ? '' : String(line.newLineNo)), createElement('code', { style: diffCodeStyle }, `${diffLinePrefix(line.kind)}${line.text}`))));
369
377
  }
370
- function FileDiffViewer({ path, staged, diff, onClose }) {
371
- return createElement('div', { style: diffOverlayStyle, onPointerDown: backdropPointerDownHandler(onClose) }, createElement('section', { role: 'dialog', 'aria-modal': true, 'aria-label': '文件 Diff', style: diffStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', { style: fileDiffTitleStyle, title: path }, `文件 Diff · ${path}`), createElement('div', { style: rowActionsStyle }, createElement('span', { style: diffCountStyle }, staged ? '已暂存' : '未暂存'), createElement('button', { type: 'button', onClick: onClose, className: gitPanelClass.action, style: iconActionStyle, title: '关闭 Diff', 'aria-label': '关闭 Diff' }, '×'))), createElement('div', { style: diffBodyStyle }, createElement('section', { style: diffDiffSectionStyle }, createElement('div', { style: diffSectionHeaderStyle }, createElement('strong', undefined, staged ? '暂存区 Diff(相对 HEAD)' : '工作区 Diff'), diff.binary ? createElement('span', { style: diffBinaryStyle }, '二进制文件') : null, diff.truncated ? createElement('span', { style: diffTruncatedStyle }, '内容已截断') : null), createElement(DiffLines, { content: diff.content })))));
378
+ function FileDiffViewer({ path, staged, diff, onClose, t }) {
379
+ return createElement('div', { style: diffOverlayStyle, onPointerDown: backdropPointerDownHandler(onClose) }, createElement('section', { role: 'dialog', 'aria-modal': true, 'aria-label': t('git.fileDiff'), style: diffStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', { style: fileDiffTitleStyle, title: path }, t('git.fileDiffTitle', { path })), createElement('div', { style: rowActionsStyle }, createElement('span', { style: diffCountStyle }, staged ? t('git.staged') : t('git.unstaged')), createElement('button', { type: 'button', onClick: onClose, className: gitPanelClass.action, style: iconActionStyle, title: t('git.closeDiff'), 'aria-label': t('git.closeDiff') }, '×'))), createElement('div', { style: diffBodyStyle }, createElement('section', { style: diffDiffSectionStyle }, createElement('div', { style: diffSectionHeaderStyle }, createElement('strong', undefined, staged ? t('git.stagedDiffHead') : t('git.worktreeDiff')), diff.binary ? createElement('span', { style: diffBinaryStyle }, t('git.binaryFile')) : null, diff.truncated ? createElement('span', { style: diffTruncatedStyle }, t('git.truncated')) : null), createElement(DiffLines, { content: diff.content, t })))));
372
380
  }
373
381
  function parseDiffLines(content) {
374
382
  const lines = [];
@@ -419,7 +427,7 @@ function parseDiffFiles(content) {
419
427
  }
420
428
  return result;
421
429
  }
422
- function diffFileStatusLabel(status) { return status === 'A' ? '新增' : status === 'D' ? '删除' : status === 'R' ? '重命名' : status === 'C' ? '复制' : '修改'; }
430
+ function diffFileStatusLabel(status, t) { return status === 'A' ? t('git.statusAdded') : status === 'D' ? t('git.statusDeleted') : status === 'R' ? t('git.statusRenamed') : status === 'C' ? t('git.statusCopied') : t('git.statusModified'); }
423
431
  function diffLinePrefix(kind) { return kind === 'add' ? '+' : kind === 'remove' ? '-' : kind === 'context' ? ' ' : ''; }
424
432
  /** Diff 行的配色与 DSH 内置 DiffBlock 完全对齐:同一组状态色 + 行底色 + 左侧 3px 色条。 */
425
433
  function diffLineStyle(kind) {
@@ -433,40 +441,40 @@ function diffLineStyle(kind) {
433
441
  return { ...diffLineBaseStyle, color: dshThemeColor.labelTertiary };
434
442
  return diffLineBaseStyle;
435
443
  }
436
- function HistorySection({ history, totalCount, hasMore, loadingMore, onLoadMore, branches, busy, scope, hasRemote, onScopeChange, onSwitch, onCopy, onCopyMessage, onViewDiff, onUndo }) {
444
+ function HistorySection({ history, totalCount, hasMore, loadingMore, onLoadMore, branches, busy, scope, hasRemote, onScopeChange, onSwitch, onCopy, onCopyMessage, onViewDiff, onUndo, t }) {
437
445
  const graph = buildHistoryGraph(history);
438
446
  const graphWidth = graph.laneCount * GRAPH_LANE_WIDTH;
439
447
  const rows = [];
440
- for (const group of groupHistoryByDate(history)) {
448
+ for (const group of groupHistoryByDate(history, t)) {
441
449
  const firstIndex = group.items[0]?.index ?? 0;
442
450
  rows.push(createElement('div', { key: `date:${group.key}`, style: historyDateHeaderStyle }, createElement(GitGraphRails, { lanes: graph.rows[firstIndex]?.top ?? [], width: graphWidth, minHeight: 16 }), createElement('time', { dateTime: group.key, style: historyDateHeaderTextStyle }, group.label)));
443
451
  for (const { item, index, timeLabel } of group.items) {
444
452
  rows.push(createElement(HistoryGraphRow, {
445
453
  key: item.commitHash, item, timeLabel, row: graph.rows[index] ?? EMPTY_GRAPH_ROW, width: graphWidth,
446
- busy, hasRemote, isHead: hasHeadRef(item), onCopy, onCopyMessage, onViewDiff, onUndo,
454
+ busy, hasRemote, isHead: hasHeadRef(item), onCopy, onCopyMessage, onViewDiff, onUndo, t,
447
455
  }));
448
456
  }
449
457
  }
450
- return createElement('section', { style: sectionStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', { title: '提交图:彩色实线=泳道(分支拓扑),蓝色虚线=尚未推送到远程的提交;鼠标悬浮节点可看该提交的归属与分支' }, `Git 版本 (${totalCount})`), createElement('div', { style: historyHeaderActionsStyle }, createElement('select', {
451
- value: scope, disabled: busy, className: gitPanelClass.select, style: scopeSelectStyle, title: '版本范围:只列当前分支,或列出全部本地分支与远程跟踪分支', 'aria-label': '版本范围',
458
+ return createElement('section', { style: sectionStyle }, createElement('div', { style: sectionHeaderStyle }, createElement('strong', { title: t('git.graphLegend') }, t('git.versionCount', { count: totalCount })), createElement('div', { style: historyHeaderActionsStyle }, createElement('select', {
459
+ value: scope, disabled: busy, className: gitPanelClass.select, style: scopeSelectStyle, title: t('git.scopeHint'), 'aria-label': t('git.scopeLabel'),
452
460
  onChange: (event) => onScopeChange(event.currentTarget.value === 'all' ? 'all' : 'head'),
453
- }, createElement('option', { value: 'head' }, '当前分支'), createElement('option', { value: 'all' }, '全部分支')), branches === null ? null : createElement('select', { value: branches.currentBranch, disabled: busy, className: gitPanelClass.select, style: branchSelectStyle, title: '切换分支', 'aria-label': '切换分支', onChange: (event) => onSwitch(event.currentTarget.value) }, ...branches.local.map((branch) => createElement('option', { key: branch.name, value: branch.name }, branch.name))))), history.length === 0
454
- ? createElement('div', { style: mutedStyle }, '暂无提交')
461
+ }, createElement('option', { value: 'head' }, t('git.currentBranch')), createElement('option', { value: 'all' }, t('git.allBranches'))), branches === null ? null : createElement('select', { value: branches.currentBranch, disabled: busy, className: gitPanelClass.select, style: branchSelectStyle, title: t('git.switchBranch'), 'aria-label': t('git.switchBranch'), onChange: (event) => onSwitch(event.currentTarget.value) }, ...branches.local.map((branch) => createElement('option', { key: branch.name, value: branch.name }, branch.name))))), history.length === 0
462
+ ? createElement('div', { style: mutedStyle }, t('git.noCommits'))
455
463
  // 行间不能留间距:每行的竖线只画到行底,一旦行与行之间有缝隙,泳道就会断成一段一段。
456
- : createElement('div', { style: historyListStyle }, ...rows), hasMore ? createElement('button', { type: 'button', disabled: busy || loadingMore, onClick: onLoadMore, className: `${gitPanelClass.button} ${gitPanelClass.field}`, style: loadMoreButtonStyle }, loadingMore ? '正在加载…' : '查看更多版本(每次 100 条)') : null);
464
+ : createElement('div', { style: historyListStyle }, ...rows), hasMore ? createElement('button', { type: 'button', disabled: busy || loadingMore, onClick: onLoadMore, className: `${gitPanelClass.button} ${gitPanelClass.field}`, style: loadMoreButtonStyle }, loadingMore ? t('git.loading') : t('git.loadMoreVersions')) : null);
457
465
  }
458
466
  const EMPTY_GRAPH_ROW = { lane: 0, color: 0, through: [], merges: [], branches: [], top: [], bottom: [] };
459
- function HistoryGraphRow({ item, timeLabel, row, width, busy, hasRemote, isHead, onCopy, onCopyMessage, onViewDiff, onUndo }) {
467
+ function HistoryGraphRow({ item, timeLabel, row, width, busy, hasRemote, isHead, onCopy, onCopyMessage, onViewDiff, onUndo, t }) {
460
468
  const refs = sortHistoryRefs(item.refs ?? []);
461
- const nodeTitle = describeCommitNode(item, refs, hasRemote);
469
+ const nodeTitle = describeCommitNode(item, refs, hasRemote, t);
462
470
  const [menuOpen, setMenuOpen] = useState(false);
463
471
  const menuRef = useRef(null);
464
472
  useDismissOnOutsidePointer(menuRef, menuOpen, () => setMenuOpen(false));
465
473
  const runMenu = (action) => () => { setMenuOpen(false); action(); };
466
474
  return createElement('div', { className: gitPanelClass.row, style: historyRowStyle }, createElement('div', { style: { ...graphGutterStyle, width }, 'aria-hidden': 'true' }, createElement(GitGraphTrack, { row, width, head: isHead, title: nodeTitle }), refs.length === 0 ? null : createElement(GitGraphRails, { lanes: row.bottom, width, fill: true })), createElement('div', { style: historyRowBodyStyle }, createElement('div', { style: historyRowMainStyle }, createElement('code', { style: hashStyle }, item.commitHash.slice(0, 8)), createElement('span', { style: fileNameStyle, title: item.subject }, item.subject), createElement('time', {
467
475
  style: historyTimeStyle, dateTime: item.authoredAt,
468
- title: item.authorName === '' ? item.authoredAt : `${item.authoredAt} · 作者 ${item.authorName}`,
469
- }, timeLabel), createElement('div', { ref: menuRef, style: menuStyle }, createElement('button', { type: 'button', className: gitPanelClass.menuTrigger, style: iconActionStyle, title: '版本操作菜单', 'aria-label': '版本操作菜单', 'aria-haspopup': 'menu', 'aria-expanded': menuOpen, onClick: () => setMenuOpen((value) => !value) }, '⋯'), menuOpen && createElement('div', { role: 'menu', 'aria-label': '版本操作菜单', className: gitPanelClass.menu, style: menuPopupStyle }, createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onViewDiff(item.commitHash)), className: gitPanelClass.menuItem, style: menuItemStyle }, '查看更改文件与 Diff'), createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onCopy(item.commitHash)), className: gitPanelClass.menuItem, style: menuItemStyle }, '复制 Commit Hash'), createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onCopyMessage(buildCommitMessageText(item.subject, item.body))), className: gitPanelClass.menuItem, style: menuItemStyle }, '复制提交信息'), createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onCopy(item.commitHash)), className: gitPanelClass.menuItem, style: menuItemStyle }, '复制 Git 版本号'), isHead ? createElement('button', { type: 'button', role: 'menuitem', disabled: busy, onClick: runMenu(onUndo), className: `${gitPanelClass.menuItem} ${gitPanelClass.menuItemDanger}`, style: menuItemStyle }, '撤销上次提交') : null))), refs.length === 0 ? null : createElement('div', { style: historyRefListStyle }, ...refs.map((ref) => createElement('span', { key: `${ref.kind}:${ref.name}`, title: refTitle(ref), className: gitPanelClass.ref, style: historyRefPillStyle(ref.kind, ref.remoteName) }, `${refGlyph(ref.kind)} ${ref.name}`)))));
476
+ title: item.authorName === '' ? item.authoredAt : t('git.authorSuffix', { date: item.authoredAt, author: item.authorName }),
477
+ }, timeLabel), createElement('div', { ref: menuRef, style: menuStyle }, createElement('button', { type: 'button', className: gitPanelClass.menuTrigger, style: iconActionStyle, title: t('git.versionMenu'), 'aria-label': t('git.versionMenu'), 'aria-haspopup': 'menu', 'aria-expanded': menuOpen, onClick: () => setMenuOpen((value) => !value) }, '⋯'), menuOpen && createElement('div', { role: 'menu', 'aria-label': t('git.versionMenu'), className: gitPanelClass.menu, style: menuPopupStyle }, createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onViewDiff(item.commitHash)), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.viewChangesAndDiff')), createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onCopy(item.commitHash)), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.copyCommitHash')), createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onCopyMessage(buildCommitMessageText(item.subject, item.body))), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.copyCommitMessage')), createElement('button', { type: 'button', role: 'menuitem', onClick: runMenu(() => onCopy(item.commitHash)), className: gitPanelClass.menuItem, style: menuItemStyle }, t('git.copyVersionHash')), isHead ? createElement('button', { type: 'button', role: 'menuitem', disabled: busy, onClick: runMenu(onUndo), className: `${gitPanelClass.menuItem} ${gitPanelClass.menuItemDanger}`, style: menuItemStyle }, t('git.undoLastCommit')) : null))), refs.length === 0 ? null : createElement('div', { style: historyRefListStyle }, ...refs.map((ref) => createElement('span', { key: `${ref.kind}:${ref.name}`, title: refTitle(ref, t), className: gitPanelClass.ref, style: historyRefPillStyle(ref.kind, ref.remoteName) }, `${refGlyph(ref.kind)} ${ref.name}`)))));
470
478
  }
471
479
  /** 标签顺序对齐 VS Code:当前分支 → 本地分支 → 远程分支 → 标签,同一提交的多个引用顺序稳定。 */
472
480
  function sortHistoryRefs(refs) {
@@ -523,30 +531,30 @@ function hasHeadRef(item) {
523
531
  function refGlyph(kind) {
524
532
  return kind === 'head' ? '●' : kind === 'remote' ? '☁' : kind === 'tag' ? '⚑' : '⑂';
525
533
  }
526
- function refTitle(ref) {
527
- const kind = ref.kind === 'head' ? '当前分支' : ref.kind === 'remote' ? '远程分支' : ref.kind === 'tag' ? '标签' : '本地分支';
528
- return `${kind}:${ref.name}`;
534
+ function refTitle(ref, t) {
535
+ const kind = ref.kind === 'head' ? t('git.currentBranch') : ref.kind === 'remote' ? t('git.remoteBranch') : ref.kind === 'tag' ? t('git.tag') : t('git.localBranch');
536
+ return t('git.refTitle', { kind, name: ref.name });
529
537
  }
530
538
  /** 归属不单独显示文字,只作为节点 tooltip:颜色与虚实已经表达了归属,说明放在悬浮提示里。 */
531
- function describeCommitOrigin(origin, hasRemote) {
539
+ function describeCommitOrigin(origin, hasRemote, t) {
532
540
  if (origin === undefined)
533
541
  return null;
534
542
  if (origin === 'local')
535
- return hasRemote ? '本地提交:只在本地分支上,尚未推送到远程(蓝色虚线)' : '本地提交:只在本地分支上(当前仓库没有远程,蓝色虚线)';
543
+ return hasRemote ? t('git.originLocalWithRemote') : t('git.originLocalOnly');
536
544
  if (origin === 'synced')
537
- return '已同步:当前分支与远程跟踪分支都包含该提交(彩色实线)';
545
+ return t('git.originSynced');
538
546
  if (origin === 'remote')
539
- return '远程提交:只有远程跟踪分支包含该提交,本地还没有(可先 Fetch/Pull)';
540
- return '其他分支:只有其他本地分支包含该提交,当前分支与远程都没有(蓝色虚线)';
547
+ return t('git.originRemote');
548
+ return t('git.originOtherBranch');
541
549
  }
542
550
  /** 悬浮节点时显示:短哈希、归属状态、该提交上的分支与标签名称。 */
543
- function describeCommitNode(item, refs, hasRemote) {
544
- const status = describeCommitOrigin(item.origin, hasRemote) ?? '归属未知:Host 未返回提交归属(按泳道配色)';
551
+ function describeCommitNode(item, refs, hasRemote, t) {
552
+ const status = describeCommitOrigin(item.origin, hasRemote, t) ?? t('git.originUnknown');
545
553
  const parts = [`${item.commitHash.slice(0, 8)} ${item.subject}`, status];
546
554
  if (refs.length > 0)
547
- parts.push(`分支与标签:${refs.map((ref) => refTitle(ref)).join(';')}`);
555
+ parts.push(t('git.branchesAndTags', { refs: refs.map((ref) => refTitle(ref, t)).join(t('git.refSeparator')) }));
548
556
  if (item.authorName !== '')
549
- parts.push(`作者:${item.authorName}`);
557
+ parts.push(t('git.author', { name: item.authorName }));
550
558
  return parts.join('\n');
551
559
  }
552
560
  function buildChangeTree(items) {
@@ -871,10 +879,10 @@ async function copyText(value) { try {
871
879
  catch {
872
880
  return false;
873
881
  } }
874
- function groupHistoryByDate(history) {
882
+ function groupHistoryByDate(history, t) {
875
883
  const groups = [];
876
884
  for (const [index, item] of history.entries()) {
877
- const timestamp = formatHistoryTimestamp(item.authoredAt);
885
+ const timestamp = formatHistoryTimestamp(item.authoredAt, t);
878
886
  const current = groups.at(-1);
879
887
  if (current?.key === timestamp.key) {
880
888
  current.items.push({ item, index, timeLabel: timestamp.timeLabel });
@@ -884,13 +892,13 @@ function groupHistoryByDate(history) {
884
892
  }
885
893
  return groups;
886
894
  }
887
- function formatHistoryTimestamp(value) {
895
+ function formatHistoryTimestamp(value, t) {
888
896
  const timestamp = Date.parse(value);
889
897
  if (Number.isNaN(timestamp))
890
- return { key: 'unknown', dateLabel: '未知日期', timeLabel: '未知时间' };
898
+ return { key: 'unknown', dateLabel: t('git.unknownDate'), timeLabel: t('git.unknownTime') };
891
899
  const parts = new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }).formatToParts(timestamp);
892
900
  const get = (type) => parts.find((part) => part.type === type)?.value ?? '';
893
- return { key: `${get('year')}-${get('month')}-${get('day')}`, dateLabel: `${get('month')}月${get('day')}日`, timeLabel: `${get('hour')}:${get('minute')}` };
901
+ return { key: `${get('year')}-${get('month')}-${get('day')}`, dateLabel: t('git.dateLabel', { month: get('month'), day: get('day') }), timeLabel: `${get('hour')}:${get('minute')}` };
894
902
  }
895
903
  function buildCommitMessageText(subject, body) { const normalizedSubject = subject.trim(); const normalizedBody = body.trim(); return normalizedBody ? `${normalizedSubject}\n\n${normalizedBody}` : normalizedSubject; }
896
904
  const REMOTE_REF_PALETTE = ['#8b5cf6', '#ef4444', '#10b981', '#f59e0b', '#06b6d4', '#ec4899'];
@@ -927,8 +935,8 @@ const panelStyle = { position: 'relative', userSelect: 'none', boxSizing: 'borde
927
935
  const headerStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, minHeight: 28 };
928
936
  const tabTitleStyle = { display: 'inline-flex', alignItems: 'center', minWidth: 0, color: dshThemeColor.labelPrimary, fontSize: 12 };
929
937
  const headerActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 4 };
930
- // SegmentedControl 自带 indicator 与键盘走查,这里只负责在单列布局下占位与对齐。
931
- const columnSwitchStyle = { display: 'inline-flex', alignItems: 'center', minWidth: 0 };
938
+ // SegmentedControl 自带 indicator 与键盘走查;外层占满面板宽度后再将控件居中。
939
+ const columnSwitchStyle = { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', minWidth: 0 };
932
940
  const summaryStyle = { color: dshThemeColor.labelSecondary, fontSize: 12 };
933
941
  const contentGridStyle = { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', alignItems: 'start', gap: 12 };
934
942
  const columnStyle = { display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 };
@@ -1002,13 +1010,13 @@ const menuItemStyle = { padding: '6px 8px' };
1002
1010
  export const gitManagementFeature = {
1003
1011
  descriptor: {
1004
1012
  name: 'gitManagement', version: '0.1.0', enabledByDefault: true, dependencies: [], runtime: 'client',
1005
- ui: { label: 'Git 仓库管理', description: '查看改动并管理提交', order: 40, defaultOpen: false },
1013
+ ui: { label: 'Git repository management', labelKey: 'feature.gitManagement.label', description: 'View changes and manage commits', descriptionKey: 'feature.gitManagement.description', order: 40, defaultOpen: false },
1006
1014
  },
1007
1015
  start(context) {
1008
1016
  const uiContext = context.services.uiContext;
1009
1017
  if (uiContext === undefined)
1010
1018
  throw new Error('Git 管理模块缺少 DSH UI 上下文');
1011
- context.resources.add(registerGitManagementUi(uiContext, { rpc: context.services.rpc, remote: context.services.remote }));
1019
+ context.resources.add(registerGitManagementUi(uiContext, { rpc: context.services.rpc, remote: context.services.remote, locale: context.services.locale }));
1012
1020
  },
1013
1021
  };
1014
1022
  //# sourceMappingURL=git-management.js.map