@jingyi0605/codingns4dsh 0.2.1-beta.8 → 0.2.1-beta.9

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 (223) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +7 -3
  3. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.d.ts.map +1 -1
  4. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.js +26 -1
  5. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.js.map +1 -1
  6. package/data/build/dist/client/account-bar.d.ts.map +1 -1
  7. package/data/build/dist/client/account-bar.js +33 -21
  8. package/data/build/dist/client/account-bar.js.map +1 -1
  9. package/data/build/dist/client/avatar/desktop-bridge.js +1 -1
  10. package/data/build/dist/client/avatar/desktop-bridge.js.map +1 -1
  11. package/data/build/dist/client/avatar/desktop-view.d.ts +3 -1
  12. package/data/build/dist/client/avatar/desktop-view.d.ts.map +1 -1
  13. package/data/build/dist/client/avatar/desktop-view.js +31 -12
  14. package/data/build/dist/client/avatar/desktop-view.js.map +1 -1
  15. package/data/build/dist/client/avatar/notification-bubble.d.ts +7 -1
  16. package/data/build/dist/client/avatar/notification-bubble.d.ts.map +1 -1
  17. package/data/build/dist/client/avatar/notification-bubble.js +68 -33
  18. package/data/build/dist/client/avatar/notification-bubble.js.map +1 -1
  19. package/data/build/dist/client/bundle.js +1626 -303
  20. package/data/build/dist/client/bundle.js.map +1 -1
  21. package/data/build/dist/client/cli-slots.d.ts.map +1 -1
  22. package/data/build/dist/client/cli-slots.js +26 -2
  23. package/data/build/dist/client/cli-slots.js.map +1 -1
  24. package/data/build/dist/client/client.assistant-notifications.js.map +1 -1
  25. package/data/build/dist/client/client.delegate-command.js +6 -6
  26. package/data/build/dist/client/client.delegate-command.js.map +1 -1
  27. package/data/build/dist/client/client.native-workspace-store.js +39 -3
  28. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  29. package/data/build/dist/client/client.session-translation.js +54 -0
  30. package/data/build/dist/client/client.session-translation.js.map +1 -0
  31. package/data/build/dist/client/client.transport.js +86 -2
  32. package/data/build/dist/client/client.transport.js.map +1 -1
  33. package/data/build/dist/client/desktop-assistant.js +217 -61
  34. package/data/build/dist/client/features/assistant-notification-store.d.ts +1 -1
  35. package/data/build/dist/client/features/assistant-notification-store.d.ts.map +1 -1
  36. package/data/build/dist/client/features/assistant-notification-store.js +1 -1
  37. package/data/build/dist/client/features/assistant-notification-store.js.map +1 -1
  38. package/data/build/dist/client/features/global-voice-assistant.d.ts.map +1 -1
  39. package/data/build/dist/client/features/global-voice-assistant.js +12 -6
  40. package/data/build/dist/client/features/global-voice-assistant.js.map +1 -1
  41. package/data/build/dist/client/features/index.d.ts +1 -0
  42. package/data/build/dist/client/features/index.d.ts.map +1 -1
  43. package/data/build/dist/client/features/index.js +3 -0
  44. package/data/build/dist/client/features/index.js.map +1 -1
  45. package/data/build/dist/client/features/peer-host.d.ts.map +1 -1
  46. package/data/build/dist/client/features/peer-host.js +99 -17
  47. package/data/build/dist/client/features/peer-host.js.map +1 -1
  48. package/data/build/dist/client/features/session-translation.d.ts +3 -0
  49. package/data/build/dist/client/features/session-translation.d.ts.map +1 -0
  50. package/data/build/dist/client/features/session-translation.js +116 -0
  51. package/data/build/dist/client/features/session-translation.js.map +1 -0
  52. package/data/build/dist/client/index.d.ts.map +1 -1
  53. package/data/build/dist/client/index.js +6 -1
  54. package/data/build/dist/client/index.js.map +1 -1
  55. package/data/build/dist/client/locales/panels.d.ts.map +1 -1
  56. package/data/build/dist/client/locales/panels.js +62 -0
  57. package/data/build/dist/client/locales/panels.js.map +1 -1
  58. package/data/build/dist/client/session-file-links.d.ts +11 -0
  59. package/data/build/dist/client/session-file-links.d.ts.map +1 -0
  60. package/data/build/dist/client/{peer-host-file-links.js → session-file-links.js} +13 -3
  61. package/data/build/dist/client/session-file-links.js.map +1 -0
  62. package/data/build/dist/client/session-translation-chat.d.ts +6 -0
  63. package/data/build/dist/client/session-translation-chat.d.ts.map +1 -0
  64. package/data/build/dist/client/session-translation-chat.js +686 -0
  65. package/data/build/dist/client/session-translation-chat.js.map +1 -0
  66. package/data/build/dist/client/workspace-session-visibility-dom.d.ts.map +1 -1
  67. package/data/build/dist/client/workspace-session-visibility-dom.js +23 -7
  68. package/data/build/dist/client/workspace-session-visibility-dom.js.map +1 -1
  69. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.d.ts +1 -1
  70. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.d.ts.map +1 -1
  71. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.js +28 -2
  72. package/data/build/dist/dsh-capabilities/client/assistant-session-navigation-adapter.js.map +1 -1
  73. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts +21 -0
  74. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts.map +1 -1
  75. package/data/build/dist/host/cli-adapters/acp-cli-driver.js +100 -3
  76. package/data/build/dist/host/cli-adapters/acp-cli-driver.js.map +1 -1
  77. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +10 -1
  78. package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
  79. package/data/build/dist/host/cli-adapters/codex-driver.js +73 -14
  80. package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
  81. package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts +8 -1
  82. package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts.map +1 -1
  83. package/data/build/dist/host/cli-adapters/command-code-acp-loader.js +45 -2
  84. package/data/build/dist/host/cli-adapters/command-code-acp-loader.js.map +1 -1
  85. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts +8 -2
  86. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
  87. package/data/build/dist/host/cli-adapters/command-code-driver.js +32 -3
  88. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  89. package/data/build/dist/host/cli-adapters/command-code-history.d.ts +27 -0
  90. package/data/build/dist/host/cli-adapters/command-code-history.d.ts.map +1 -1
  91. package/data/build/dist/host/cli-adapters/command-code-history.js +131 -1
  92. package/data/build/dist/host/cli-adapters/command-code-history.js.map +1 -1
  93. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.js +9 -9
  94. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.js.map +1 -1
  95. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +11 -0
  96. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  97. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +79 -7
  98. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  99. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  100. package/data/build/dist/host/cli-adapters/feature.js +286 -19
  101. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  102. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  103. package/data/build/dist/host/cli-adapters/grok-driver.js +108 -47
  104. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  105. package/data/build/dist/host/cli-adapters/legacy-session-settings.d.ts.map +1 -1
  106. package/data/build/dist/host/cli-adapters/legacy-session-settings.js +7 -2
  107. package/data/build/dist/host/cli-adapters/legacy-session-settings.js.map +1 -1
  108. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +4 -2
  109. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts.map +1 -1
  110. package/data/build/dist/host/cli-adapters/opencode-driver.js +78 -31
  111. package/data/build/dist/host/cli-adapters/opencode-driver.js.map +1 -1
  112. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.d.ts +1 -1
  113. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.d.ts.map +1 -1
  114. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js +63 -6
  115. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js.map +1 -1
  116. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +5 -1
  117. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts.map +1 -1
  118. package/data/build/dist/host/cli-adapters/provider-subscription.js +90 -25
  119. package/data/build/dist/host/cli-adapters/provider-subscription.js.map +1 -1
  120. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  121. package/data/build/dist/host/cli-adapters/registry.js +22 -5
  122. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  123. package/data/build/dist/host/cli-adapters/session-store.d.ts +1 -0
  124. package/data/build/dist/host/cli-adapters/session-store.d.ts.map +1 -1
  125. package/data/build/dist/host/cli-adapters/session-store.js +3 -0
  126. package/data/build/dist/host/cli-adapters/session-store.js.map +1 -1
  127. package/data/build/dist/host/cli-bridge/bridge-server.js +2 -2
  128. package/data/build/dist/host/cli-bridge/bridge-server.js.map +1 -1
  129. package/data/build/dist/host/cli-bridge/command-code-mod.js +21 -21
  130. package/data/build/dist/host/cli-bridge/command-code-mod.js.map +1 -1
  131. package/data/build/dist/host/cli-bridge/dispatch.js +19 -19
  132. package/data/build/dist/host/cli-bridge/dispatch.js.map +1 -1
  133. package/data/build/dist/host/cli-bridge/injections.d.ts +32 -0
  134. package/data/build/dist/host/cli-bridge/injections.d.ts.map +1 -1
  135. package/data/build/dist/host/cli-bridge/injections.js +137 -1
  136. package/data/build/dist/host/cli-bridge/injections.js.map +1 -1
  137. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js +20 -20
  138. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js.map +1 -1
  139. package/data/build/dist/host/desktop-assistant/controller.d.ts +1 -0
  140. package/data/build/dist/host/desktop-assistant/controller.d.ts.map +1 -1
  141. package/data/build/dist/host/desktop-assistant/controller.js +21 -3
  142. package/data/build/dist/host/desktop-assistant/controller.js.map +1 -1
  143. package/data/build/dist/host/desktop-assistant/mac-agent.d.ts.map +1 -1
  144. package/data/build/dist/host/desktop-assistant/mac-agent.js +15 -3
  145. package/data/build/dist/host/desktop-assistant/mac-agent.js.map +1 -1
  146. package/data/build/dist/host/desktop-assistant/win-agent.d.ts.map +1 -1
  147. package/data/build/dist/host/desktop-assistant/win-agent.js +21 -3
  148. package/data/build/dist/host/desktop-assistant/win-agent.js.map +1 -1
  149. package/data/build/dist/host/features/assistant-notifications.d.ts.map +1 -1
  150. package/data/build/dist/host/features/assistant-notifications.js +12 -4
  151. package/data/build/dist/host/features/assistant-notifications.js.map +1 -1
  152. package/data/build/dist/host/features/index.d.ts +1 -0
  153. package/data/build/dist/host/features/index.d.ts.map +1 -1
  154. package/data/build/dist/host/features/index.js +3 -0
  155. package/data/build/dist/host/features/index.js.map +1 -1
  156. package/data/build/dist/host/features/peer-host.d.ts.map +1 -1
  157. package/data/build/dist/host/features/peer-host.js +11 -4
  158. package/data/build/dist/host/features/peer-host.js.map +1 -1
  159. package/data/build/dist/host/features/session-translation-service.d.ts +31 -0
  160. package/data/build/dist/host/features/session-translation-service.d.ts.map +1 -0
  161. package/data/build/dist/host/features/session-translation-service.js +451 -0
  162. package/data/build/dist/host/features/session-translation-service.js.map +1 -0
  163. package/data/build/dist/host/features/session-translation.d.ts +5 -0
  164. package/data/build/dist/host/features/session-translation.d.ts.map +1 -0
  165. package/data/build/dist/host/features/session-translation.js +37 -0
  166. package/data/build/dist/host/features/session-translation.js.map +1 -0
  167. package/data/build/dist/host/features/types.d.ts +3 -0
  168. package/data/build/dist/host/features/types.d.ts.map +1 -1
  169. package/data/build/dist/host/image-artifact-store.d.ts +21 -0
  170. package/data/build/dist/host/image-artifact-store.d.ts.map +1 -0
  171. package/data/build/dist/host/image-artifact-store.js +136 -0
  172. package/data/build/dist/host/image-artifact-store.js.map +1 -0
  173. package/data/build/dist/host/index.d.ts.map +1 -1
  174. package/data/build/dist/host/index.js +3 -0
  175. package/data/build/dist/host/index.js.map +1 -1
  176. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.d.ts +1 -1
  177. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.d.ts.map +1 -1
  178. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.js +2 -0
  179. package/data/build/dist/host/modules/peer-host/peer-host-native-protocol.js.map +1 -1
  180. package/data/build/dist/host/native-session-bridge.d.ts +16 -1
  181. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  182. package/data/build/dist/host/native-session-bridge.js +47 -0
  183. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  184. package/data/build/dist/host/rpc.js +3 -3
  185. package/data/build/dist/host/rpc.js.map +1 -1
  186. package/data/build/dist/host/session-changes.d.ts.map +1 -1
  187. package/data/build/dist/host/session-changes.js +196 -13
  188. package/data/build/dist/host/session-changes.js.map +1 -1
  189. package/data/build/dist/host/settings.d.ts.map +1 -1
  190. package/data/build/dist/host/settings.js +8 -0
  191. package/data/build/dist/host/settings.js.map +1 -1
  192. package/data/build/dist/shared/assistant-notifications.d.ts +2 -2
  193. package/data/build/dist/shared/assistant-notifications.d.ts.map +1 -1
  194. package/data/build/dist/shared/contracts/cli-adapter.d.ts +25 -2
  195. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  196. package/data/build/dist/shared/contracts/config.d.ts +6 -0
  197. package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
  198. package/data/build/dist/shared/contracts/config.js +3 -0
  199. package/data/build/dist/shared/contracts/config.js.map +1 -1
  200. package/data/build/dist/shared/contracts/session-translation.d.ts +58 -0
  201. package/data/build/dist/shared/contracts/session-translation.d.ts.map +1 -0
  202. package/data/build/dist/shared/contracts/session-translation.js +23 -0
  203. package/data/build/dist/shared/contracts/session-translation.js.map +1 -0
  204. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  205. package/data/build/dist/shared/contracts/version.js +1 -1
  206. package/data/build/dist/shared/delegation-carrier.js +6 -6
  207. package/data/build/dist/shared/delegation-carrier.js.map +1 -1
  208. package/data/build/dist/shared/desktop-assistant.d.ts +10 -4
  209. package/data/build/dist/shared/desktop-assistant.d.ts.map +1 -1
  210. package/data/build/dist/shared/desktop-assistant.js +28 -8
  211. package/data/build/dist/shared/desktop-assistant.js.map +1 -1
  212. package/data/build/dist/shared/index.d.ts +2 -1
  213. package/data/build/dist/shared/index.d.ts.map +1 -1
  214. package/data/build/dist/shared/index.js +2 -1
  215. package/data/build/dist/shared/index.js.map +1 -1
  216. package/package.json +2 -2
  217. package/profile/README.md +2 -2
  218. package/profile/package.json +2 -2
  219. package/profile/version.json +1 -1
  220. package/version.json +1 -1
  221. package/data/build/dist/client/peer-host-file-links.d.ts +0 -8
  222. package/data/build/dist/client/peer-host-file-links.d.ts.map +0 -1
  223. package/data/build/dist/client/peer-host-file-links.js.map +0 -1
@@ -7555,6 +7555,7 @@ window.__ModuleLoader__.load({
7555
7555
  var module = { exports: {} };
7556
7556
  var exports = module.exports;
7557
7557
  const require_assistant_notifications = require("@jingyi0605/codingns4dsh/client.assistant-notifications.js");
7558
+ const require_session_translation = require("@jingyi0605/codingns4dsh/client.session-translation.js");
7558
7559
  //#region src/shared/contracts/version.ts
7559
7560
  /** 当前经过完整验证的 DSH 版本;源文件由根目录 version.json 同步。 */
7560
7561
  const DSH_VERSION = "0.2.1-alpha.2";
@@ -7588,7 +7589,7 @@ window.__ModuleLoader__.load({
7588
7589
  return /^0\.1\.5(?:-|$)/u.test(version);
7589
7590
  }
7590
7591
  /** Codingns4DSH 插件自身的 npm 版本。 */
7591
- const CODINGNS_VERSION = "0.2.1-beta.8";
7592
+ const CODINGNS_VERSION = "0.2.1-beta.9";
7592
7593
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
7593
7594
  function isDshVersionCompatible(version) {
7594
7595
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -7833,8 +7834,10 @@ window.__ModuleLoader__.load({
7833
7834
  const CODINGNS_FILE_MANAGEMENT_FIELD = "fileManagement";
7834
7835
  const CODINGNS_MOBILE_ACCESS_FIELD = "mobileAccess";
7835
7836
  const CODINGNS_SUBSCRIPTION_USAGE_FIELD = "subscriptionUsage";
7837
+ const CODINGNS_SESSION_TRANSLATION_FIELD = "sessionTranslation";
7836
7838
  const CODINGNS_ASSISTANT_FIELD = "assistant";
7837
- const DEFAULT_CODINGNS_CONTROL_BASE_URLS = ["https://channel.codingns.com:1443"];
7839
+ const DEFAULT_CODINGNS_CONTROL_BASE_URL = "https://channel.codingns.com:1443";
7840
+ const DEFAULT_CODINGNS_CONTROL_BASE_URLS = [DEFAULT_CODINGNS_CONTROL_BASE_URL];
7838
7841
  /** 控制站的网页登录地址,用于注册 Codingns4DSH 账号。 */
7839
7842
  const CODINGNS_CONTROL_STATION_URL = "https://channel.codingns.com:1443";
7840
7843
  /** 独立 H5 登录页面地址;登录控制站后可从设置页复制给其他设备。 */
@@ -7868,7 +7871,28 @@ window.__ModuleLoader__.load({
7868
7871
  quickPhrases: DEFAULT_QUICK_PHRASES.map((phrase) => ({ ...phrase })),
7869
7872
  quickPhrasesSeeded: true
7870
7873
  };
7871
- [...DEFAULT_CODINGNS_CONTROL_BASE_URLS];
7874
+ const DEFAULT_CODINGNS_SETTINGS = {
7875
+ controlBaseUrl: DEFAULT_CODINGNS_CONTROL_BASE_URL,
7876
+ controlBaseUrls: [...DEFAULT_CODINGNS_CONTROL_BASE_URLS],
7877
+ modules: {},
7878
+ agentAdapters: {},
7879
+ agentAdapterPreferences: {},
7880
+ subagentBridge: DEFAULT_SUBAGENT_BRIDGE_SETTINGS,
7881
+ sessionTranslation: require_session_translation.DEFAULT_SESSION_TRANSLATION_SETTINGS,
7882
+ terminalEnhancement: DEFAULT_TERMINAL_ENHANCEMENT_SETTINGS,
7883
+ workspaceSessionEnhancement: DEFAULT_WORKSPACE_SESSION_ENHANCEMENT_SETTINGS,
7884
+ fileManagement: DEFAULT_FILE_MANAGEMENT_SETTINGS,
7885
+ mobileAccess: DEFAULT_MOBILE_ACCESS_SETTINGS,
7886
+ subscriptionUsage: DEFAULT_SUBSCRIPTION_USAGE_SETTINGS,
7887
+ assistant: DEFAULT_ASSISTANT_SETTINGS,
7888
+ lanAccessDsh: {
7889
+ autoStart: false,
7890
+ listenHost: "0.0.0.0",
7891
+ listenPort: 13080,
7892
+ dshPort: 0,
7893
+ pwa: DEFAULT_LAN_ACCESS_DSH_PWA_SETTINGS
7894
+ }
7895
+ };
7872
7896
  function captureRestartFeatureStates(descriptors, settings, dshVersion) {
7873
7897
  const states = {};
7874
7898
  for (const descriptor of descriptors) if (descriptor.activation === "restart") states[descriptor.name] = isFeatureDshVersionCompatible(descriptor, dshVersion) && isFeatureEnabled(descriptor, settings);
@@ -8035,6 +8059,12 @@ window.__ModuleLoader__.load({
8035
8059
  return CODINGNS_MODULES_FIELD;
8036
8060
  }
8037
8061
  });
8062
+ Object.defineProperty(exports, "CODINGNS_SESSION_TRANSLATION_FIELD", {
8063
+ enumerable: true,
8064
+ get: function() {
8065
+ return CODINGNS_SESSION_TRANSLATION_FIELD;
8066
+ }
8067
+ });
8038
8068
  Object.defineProperty(exports, "CODINGNS_SETTINGS_ENTRY_IDS", {
8039
8069
  enumerable: true,
8040
8070
  get: function() {
@@ -8089,6 +8119,12 @@ window.__ModuleLoader__.load({
8089
8119
  return DEFAULT_CODINGNS_CONTROL_BASE_URLS;
8090
8120
  }
8091
8121
  });
8122
+ Object.defineProperty(exports, "DEFAULT_CODINGNS_SETTINGS", {
8123
+ enumerable: true,
8124
+ get: function() {
8125
+ return DEFAULT_CODINGNS_SETTINGS;
8126
+ }
8127
+ });
8092
8128
  Object.defineProperty(exports, "DEFAULT_FILE_MANAGEMENT_SETTINGS", {
8093
8129
  enumerable: true,
8094
8130
  get: function() {
@@ -16194,6 +16230,59 @@ window.__ModuleLoader__.load({
16194
16230
  }
16195
16231
  });
16196
16232
 
16233
+ window.__ModuleLoader__.load({
16234
+ id: "@jingyi0605/codingns4dsh",
16235
+ chunk: "client.session-translation.js",
16236
+ factory: () => { const require = __codingnsOwnerRequire;
16237
+ var module = { exports: {} };
16238
+ var exports = module.exports;
16239
+ //#region src/shared/contracts/session-translation.ts
16240
+ const SESSION_TRANSLATION_ADAPTER_IDS = [
16241
+ "command-code",
16242
+ "claude-code",
16243
+ "kimi",
16244
+ "gemini",
16245
+ "pi",
16246
+ "codex",
16247
+ "opencode",
16248
+ "grok",
16249
+ "mcode",
16250
+ "zcode",
16251
+ "codebuddy",
16252
+ "workbuddy",
16253
+ "cursor-cli",
16254
+ "kiro-cli",
16255
+ "qoder",
16256
+ "qoder-cn",
16257
+ "antigravity",
16258
+ "doubao"
16259
+ ];
16260
+ const DEFAULT_SESSION_TRANSLATION_SETTINGS = {
16261
+ inputLanguage: "en",
16262
+ outputLanguage: "zh",
16263
+ bilingual: false
16264
+ };
16265
+ /** 所有内置外部 Agent 均可在会话模型选择器中开启翻译;DSH 原生 Agent 不在其中。 */
16266
+ function isSessionTranslationAdapter(adapterId) {
16267
+ return SESSION_TRANSLATION_ADAPTER_IDS.includes(adapterId);
16268
+ }
16269
+ //#endregion
16270
+ Object.defineProperty(exports, "DEFAULT_SESSION_TRANSLATION_SETTINGS", {
16271
+ enumerable: true,
16272
+ get: function() {
16273
+ return DEFAULT_SESSION_TRANSLATION_SETTINGS;
16274
+ }
16275
+ });
16276
+ Object.defineProperty(exports, "isSessionTranslationAdapter", {
16277
+ enumerable: true,
16278
+ get: function() {
16279
+ return isSessionTranslationAdapter;
16280
+ }
16281
+ });
16282
+ return module.exports;
16283
+ }
16284
+ });
16285
+
16197
16286
  window.__ModuleLoader__.load({
16198
16287
  id: "@jingyi0605/codingns4dsh",
16199
16288
  chunk: "client.theme.js",
@@ -17817,11 +17906,53 @@ window.__ModuleLoader__.load({
17817
17906
  "cli.thinkingLevelTitle": "Thinking level ({model})",
17818
17907
  "cli.adapterEnabled": "{name} enabled",
17819
17908
  "cli.adapterDisabled": "{name} disabled",
17909
+ "cli.translationConversation": "Translate conversation",
17910
+ "cli.translationConversationToggle": "Toggle conversation translation",
17820
17911
  "lan.fieldListenPort": "listen port",
17821
17912
  "lan.fieldDshPort": "DSH local port",
17822
17913
  "lan.fieldMustBeNumber": "{field} must be a number",
17823
17914
  "lan.fieldMustBeInteger": "{field} must be an integer from {minimum} to 65535",
17824
- "workspace.sessionSettingsSaved": "Workspace session settings saved"
17915
+ "workspace.sessionSettingsSaved": "Workspace session settings saved",
17916
+ "feature.sessionTranslation.label": "Session translation",
17917
+ "feature.sessionTranslation.description": "Translate selected external Agent requests and replies while keeping tools, commands, paths, and original history unchanged.",
17918
+ "translation.inputTitle": "Translate requests before sending",
17919
+ "translation.inputLanguage": "Request language",
17920
+ "translation.outputTitle": "Translate visible replies",
17921
+ "translation.outputLanguage": "Reply language",
17922
+ "translation.modelTitle": "Translation model",
17923
+ "translation.modelFollowDefault": "Use the default DSH model",
17924
+ "translation.modelUnavailable": "Saved model is unavailable",
17925
+ "translation.modelLoading": "Loading available DSH models…",
17926
+ "translation.modelEmpty": "No DSH text models are available.",
17927
+ "translation.modelHelp": "DeepSeek official and configured third-party models are available here. Translation requests always disable thinking.",
17928
+ "translation.detailsTitle": "Translation details",
17929
+ "translation.viewDetails": "View translation details",
17930
+ "translation.statusTranslated": "Translated",
17931
+ "translation.statusFailed": "Translation failed; original kept",
17932
+ "translation.statusNotNeeded": "Already in the target language; translation skipped",
17933
+ "translation.detectedLanguage": "Detected language",
17934
+ "translation.modelNotUsed": "Not used; translation was unnecessary",
17935
+ "translation.originalText": "Original text",
17936
+ "translation.translatedText": "Translated / sent text",
17937
+ "translation.modelUsed": "Model used",
17938
+ "translation.modelUnknown": "Model information unavailable",
17939
+ "translation.modelOfficial": "DeepSeek official",
17940
+ "translation.modelThirdParty": "Third-party",
17941
+ "translation.saveRejected": "The translation settings could not be saved.",
17942
+ "translation.saved": "Translation settings saved",
17943
+ "translation.language.zh": "简体中文",
17944
+ "translation.language.en": "English",
17945
+ "translation.language.fr": "Français",
17946
+ "translation.language.de": "Deutsch",
17947
+ "translation.language.ja": "日本語",
17948
+ "translation.adapter.claude": "Claude Code",
17949
+ "translation.adapter.codex": "Codex",
17950
+ "translation.adapter.pi": "Pi",
17951
+ "translation.adapter.opencode": "OpenCode",
17952
+ "translation.adapter.antigravity": "Antigravity",
17953
+ "translation.adapter.grok": "Grok",
17954
+ "translation.adapter.cursor": "Cursor",
17955
+ "translation.adapter.kiro": "Kiro"
17825
17956
  };
17826
17957
  const zh$9 = {
17827
17958
  "common.listSeparator": "、",
@@ -17830,11 +17961,53 @@ window.__ModuleLoader__.load({
17830
17961
  "cli.thinkingLevelTitle": "思考等级({model})",
17831
17962
  "cli.adapterEnabled": "已启用 {name}",
17832
17963
  "cli.adapterDisabled": "已停用 {name}",
17964
+ "cli.translationConversation": "翻译对话",
17965
+ "cli.translationConversationToggle": "切换对话翻译",
17833
17966
  "lan.fieldListenPort": "监听端口",
17834
17967
  "lan.fieldDshPort": "DSH 本地端口",
17835
17968
  "lan.fieldMustBeNumber": "{field} 必须是数字",
17836
17969
  "lan.fieldMustBeInteger": "{field} 必须是 {minimum} 到 65535 的整数",
17837
- "workspace.sessionSettingsSaved": "工作区会话设置已保存"
17970
+ "workspace.sessionSettingsSaved": "工作区会话设置已保存",
17971
+ "feature.sessionTranslation.label": "会话翻译",
17972
+ "feature.sessionTranslation.description": "为选定的外部 Agent 翻译请求和回复,同时保留工具、命令、路径与原始历史。",
17973
+ "translation.inputTitle": "发送前翻译请求",
17974
+ "translation.inputLanguage": "请求目标语言",
17975
+ "translation.outputTitle": "翻译界面回复",
17976
+ "translation.outputLanguage": "回复语言",
17977
+ "translation.modelTitle": "翻译模型",
17978
+ "translation.modelFollowDefault": "跟随 DSH 默认模型",
17979
+ "translation.modelUnavailable": "已保存的模型当前不可用",
17980
+ "translation.modelLoading": "正在加载可用的 DSH 模型…",
17981
+ "translation.modelEmpty": "当前没有可用的 DSH 文本模型。",
17982
+ "translation.modelHelp": "这里可以选择 DeepSeek 官方模型或已配置的第三方模型;翻译请求始终关闭思考。",
17983
+ "translation.detailsTitle": "翻译详情",
17984
+ "translation.viewDetails": "查看翻译详情",
17985
+ "translation.statusTranslated": "已翻译",
17986
+ "translation.statusFailed": "翻译失败,已保留原文",
17987
+ "translation.statusNotNeeded": "原文已是目标语言,无需翻译",
17988
+ "translation.detectedLanguage": "检测到的语言",
17989
+ "translation.modelNotUsed": "未调用,原文无需翻译",
17990
+ "translation.originalText": "原文",
17991
+ "translation.translatedText": "译文 / 实际发送文本",
17992
+ "translation.modelUsed": "实际翻译模型",
17993
+ "translation.modelUnknown": "暂无模型信息",
17994
+ "translation.modelOfficial": "DeepSeek 官方",
17995
+ "translation.modelThirdParty": "第三方",
17996
+ "translation.saveRejected": "会话翻译设置未能保存。",
17997
+ "translation.saved": "会话翻译设置已保存",
17998
+ "translation.language.zh": "简体中文",
17999
+ "translation.language.en": "英语",
18000
+ "translation.language.fr": "法语",
18001
+ "translation.language.de": "德语",
18002
+ "translation.language.ja": "日语",
18003
+ "translation.adapter.claude": "Claude Code",
18004
+ "translation.adapter.codex": "Codex",
18005
+ "translation.adapter.pi": "Pi",
18006
+ "translation.adapter.opencode": "OpenCode",
18007
+ "translation.adapter.antigravity": "Antigravity",
18008
+ "translation.adapter.grok": "Grok",
18009
+ "translation.adapter.cursor": "Cursor",
18010
+ "translation.adapter.kiro": "Kiro"
17838
18011
  };
17839
18012
  //#endregion
17840
18013
  //#region src/client/locales/peerHost.ts
@@ -20254,6 +20427,7 @@ window.__ModuleLoader__.load({
20254
20427
  const require_transport = require("@jingyi0605/codingns4dsh/client.transport.js");
20255
20428
  const require_model_catalog_cache = require("@jingyi0605/codingns4dsh/client.model-catalog-cache.js");
20256
20429
  const require_assistant_notifications = require("@jingyi0605/codingns4dsh/client.assistant-notifications.js");
20430
+ const require_session_translation = require("@jingyi0605/codingns4dsh/client.session-translation.js");
20257
20431
  const require_theme = require("@jingyi0605/codingns4dsh/client.theme.js");
20258
20432
  const require_react_dom$1 = require("@jingyi0605/codingns4dsh/client.react-dom.js");
20259
20433
  const require_manager = require("@jingyi0605/codingns4dsh/client.manager.js");
@@ -27641,7 +27815,7 @@ window.__ModuleLoader__.load({
27641
27815
  const method = channel === "/codingns" ? endpoint : channel === "/api" ? endpoint.replace(/^codingns\//u, "") : "";
27642
27816
  if (peerHostId === null) {
27643
27817
  const input = CATALOG_ENDPOINTS.has(method) ? {
27644
- ...asRecord$7(payload),
27818
+ ...asRecord$8(payload),
27645
27819
  catalogHostId: "local"
27646
27820
  } : payload;
27647
27821
  return rpc.call(channel, endpoint, input, signal);
@@ -27665,18 +27839,18 @@ window.__ModuleLoader__.load({
27665
27839
  });
27666
27840
  let envelope = null;
27667
27841
  try {
27668
- envelope = asRecord$7(JSON.parse(response.body));
27842
+ envelope = asRecord$8(JSON.parse(response.body));
27669
27843
  } catch {}
27670
27844
  if (response.status < 200 || response.status >= 300) {
27671
- const error = asRecord$7(envelope?.error);
27845
+ const error = asRecord$8(envelope?.error);
27672
27846
  return failure$1(typeof error?.code === "string" ? error.code : "PEER_HOST_PROXY_UNREACHABLE", typeof error?.message === "string" ? error.message : require_transport.resolveCodingNsTranslator(locale)("cli.peerHostRpcFailed", { status: response.status }));
27673
27847
  }
27674
- const result = asRecord$7(envelope?.result);
27848
+ const result = asRecord$8(envelope?.result);
27675
27849
  if (result?.ok === true && Object.hasOwn(result, "value")) return {
27676
27850
  ok: true,
27677
27851
  value: result.value
27678
27852
  };
27679
- const error = asRecord$7(result?.error);
27853
+ const error = asRecord$8(result?.error);
27680
27854
  if (result?.ok === false && typeof error?.code === "string" && typeof error.message === "string") return failure$1(error.code, error.message);
27681
27855
  return failure$1("PEER_HOST_RESPONSE_INVALID", require_transport.resolveCodingNsTranslator(locale)("cli.peerHostRpcInvalid"));
27682
27856
  } };
@@ -27695,7 +27869,7 @@ window.__ModuleLoader__.load({
27695
27869
  }
27696
27870
  };
27697
27871
  }
27698
- function asRecord$7(value) {
27872
+ function asRecord$8(value) {
27699
27873
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
27700
27874
  }
27701
27875
  //#endregion
@@ -28537,7 +28711,7 @@ window.__ModuleLoader__.load({
28537
28711
  }, hostStatus === null ? t("terminal.readingStatus") : t("terminal.currentStatus", {
28538
28712
  status: hostStatus.effectiveEnabled ? t("terminal.enhanced") : t("terminal.basic"),
28539
28713
  platform: platformLabel(hostStatus.platform, t)
28540
- })), (0, react.createElement)(Field, {
28714
+ })), (0, react.createElement)(Field$1, {
28541
28715
  label: t("terminal.newDefault"),
28542
28716
  help: t("terminal.defaultProfileHelp")
28543
28717
  }, (0, react.createElement)("select", {
@@ -28552,7 +28726,7 @@ window.__ModuleLoader__.load({
28552
28726
  key: profile.profileId,
28553
28727
  value: profile.profileId,
28554
28728
  disabled: !profile.available
28555
- }, profile.label))), hostStatus?.fallbackReason === void 0 ? null : (0, react.createElement)("small", { style: helpStyle }, hostStatus.fallbackReason)), (0, react.createElement)(Field, {
28729
+ }, profile.label))), hostStatus?.fallbackReason === void 0 ? null : (0, react.createElement)("small", { style: helpStyle }, hostStatus.fallbackReason)), (0, react.createElement)(Field$1, {
28556
28730
  label: t("terminal.bindingScope"),
28557
28731
  help: t("terminal.workspaceBindingHelp")
28558
28732
  }, (0, react.createElement)("select", {
@@ -28591,7 +28765,7 @@ window.__ModuleLoader__.load({
28591
28765
  value: appearance.cursorColor,
28592
28766
  disabled,
28593
28767
  onChange: (cursorColor) => updateAppearance({ cursorColor })
28594
- }), (0, react.createElement)(Field, { label: t("terminal.cursorBlink") }, (0, react.createElement)("label", { style: {
28768
+ }), (0, react.createElement)(Field$1, { label: t("terminal.cursorBlink") }, (0, react.createElement)("label", { style: {
28595
28769
  display: "flex",
28596
28770
  alignItems: "center",
28597
28771
  justifyContent: "space-between",
@@ -28619,7 +28793,7 @@ window.__ModuleLoader__.load({
28619
28793
  step: .1,
28620
28794
  disabled,
28621
28795
  onChange: (lineHeight) => updateAppearance({ lineHeight })
28622
- }), (0, react.createElement)(Field, { label: t("terminal.cursorShape") }, (0, react.createElement)("select", {
28796
+ }), (0, react.createElement)(Field$1, { label: t("terminal.cursorShape") }, (0, react.createElement)("select", {
28623
28797
  value: appearance.cursorStyle,
28624
28798
  disabled,
28625
28799
  onChange: (event) => updateAppearance({ cursorStyle: parseCursorStyle(event.currentTarget.value) }),
@@ -28634,7 +28808,7 @@ window.__ModuleLoader__.load({
28634
28808
  onChange: (scrollback) => updateAppearance({ scrollback })
28635
28809
  })));
28636
28810
  }
28637
- function Field({ label, help, children }) {
28811
+ function Field$1({ label, help, children }) {
28638
28812
  return (0, react.createElement)("div", { style: {
28639
28813
  display: "flex",
28640
28814
  flexDirection: "column",
@@ -28650,7 +28824,7 @@ window.__ModuleLoader__.load({
28650
28824
  }, "ⓘ");
28651
28825
  }
28652
28826
  function ColorField({ label, value, disabled, onChange }) {
28653
- return (0, react.createElement)(Field, { label }, (0, react.createElement)("div", { style: rowStyle$2 }, (0, react.createElement)("input", {
28827
+ return (0, react.createElement)(Field$1, { label }, (0, react.createElement)("div", { style: rowStyle$2 }, (0, react.createElement)("input", {
28654
28828
  type: "color",
28655
28829
  value,
28656
28830
  disabled,
@@ -28663,7 +28837,7 @@ window.__ModuleLoader__.load({
28663
28837
  }), (0, react.createElement)("code", { style: { flex: 1 } }, value)));
28664
28838
  }
28665
28839
  function NumberField({ label, value, min, max, step, disabled, onChange }) {
28666
- return (0, react.createElement)(Field, { label }, (0, react.createElement)("div", { style: rowStyle$2 }, (0, react.createElement)("input", {
28840
+ return (0, react.createElement)(Field$1, { label }, (0, react.createElement)("div", { style: rowStyle$2 }, (0, react.createElement)("input", {
28667
28841
  type: "number",
28668
28842
  value,
28669
28843
  min,
@@ -29123,11 +29297,11 @@ window.__ModuleLoader__.load({
29123
29297
  const iterator = (await api.follow())[Symbol.asyncIterator]();
29124
29298
  const first = await iterator.next();
29125
29299
  await iterator.return?.();
29126
- const value = asRecord$6(asRecord$6(first.value)?.value);
29300
+ const value = asRecord$7(asRecord$7(first.value)?.value);
29127
29301
  const records = Array.isArray(value?.items) ? value.items : [];
29128
29302
  const globalArchived = readStringArray(value?.archivedSessionIds);
29129
29303
  return records.flatMap((item) => {
29130
- const record = asRecord$6(item);
29304
+ const record = asRecord$7(item);
29131
29305
  const workspaceId = readString$1(record?.workspaceId);
29132
29306
  if (workspaceId === void 0) return [];
29133
29307
  const path = readString$1(record?.path);
@@ -29143,12 +29317,12 @@ window.__ModuleLoader__.load({
29143
29317
  }
29144
29318
  async function readSessionList(api) {
29145
29319
  if (api?.list === void 0) return [];
29146
- const result = asRecord$6(unwrapRemoteValue$1(await api.list({})));
29320
+ const result = asRecord$7(unwrapRemoteValue$1(await api.list({})));
29147
29321
  return (Array.isArray(result?.items) ? result.items : []).flatMap((item) => {
29148
- const record = asRecord$6(item);
29322
+ const record = asRecord$7(item);
29149
29323
  const sessionId = readString$1(record?.sessionId);
29150
29324
  if (sessionId === void 0) return [];
29151
- const titleValue = asRecord$6(asRecord$6(record?.projections)?.values)?.title;
29325
+ const titleValue = asRecord$7(asRecord$7(record?.projections)?.values)?.title;
29152
29326
  const cwd = readString$1(record?.cwd);
29153
29327
  const workspaceIdValue = readString$1(record?.workspaceId);
29154
29328
  const archivedAt = typeof record?.archivedAt === "number" && Number.isFinite(record.archivedAt) ? record.archivedAt : 0;
@@ -29220,7 +29394,7 @@ window.__ModuleLoader__.load({
29220
29394
  "value",
29221
29395
  "data"
29222
29396
  ]) {
29223
- const workspace = asRecord$6(value[key]);
29397
+ const workspace = asRecord$7(value[key]);
29224
29398
  const id = readString$1(workspace?.workspaceId) ?? readString$1(workspace?.workspaceID) ?? readString$1(workspace?.id);
29225
29399
  if (id !== void 0) return id;
29226
29400
  }
@@ -29607,8 +29781,8 @@ window.__ModuleLoader__.load({
29607
29781
  }
29608
29782
  function normalizeRemote(value) {
29609
29783
  if (!isRecord$5(value)) return {};
29610
- const workspace = asRecord$6(readRemoteProperty(value, "workspace")) ?? asRecord$6(readRemoteProperty(value, "workspaceController"));
29611
- const session = asRecord$6(readRemoteProperty(value, "session")) ?? asRecord$6(readRemoteProperty(value, "sessionController"));
29784
+ const workspace = asRecord$7(readRemoteProperty(value, "workspace")) ?? asRecord$7(readRemoteProperty(value, "workspaceController"));
29785
+ const session = asRecord$7(readRemoteProperty(value, "session")) ?? asRecord$7(readRemoteProperty(value, "sessionController"));
29612
29786
  return {
29613
29787
  ...workspace ? { workspace } : {},
29614
29788
  ...session ? { session } : {}
@@ -29631,12 +29805,12 @@ window.__ModuleLoader__.load({
29631
29805
  return result === void 0 ? [] : [result];
29632
29806
  }) : [];
29633
29807
  }
29634
- function asRecord$6(value) {
29808
+ function asRecord$7(value) {
29635
29809
  return isRecord$5(value) ? value : void 0;
29636
29810
  }
29637
29811
  /** DSH Remote 的直接调用返回 RemoteResult;测试桩和旧宿主可能直接返回 value。 */
29638
29812
  function unwrapRemoteValue$1(value) {
29639
- const record = asRecord$6(value);
29813
+ const record = asRecord$7(value);
29640
29814
  if (record === void 0 || typeof record.ok !== "boolean") return value;
29641
29815
  return record.ok ? record.value : void 0;
29642
29816
  }
@@ -29748,9 +29922,14 @@ window.__ModuleLoader__.load({
29748
29922
  });
29749
29923
  const menus = findWorkspaceMenus(dom);
29750
29924
  knownNativeMenus = new Set(menus);
29925
+ const menuContextFresh = menuContextPending;
29751
29926
  if (menus.length > 0) menuContextPending = false;
29752
29927
  const currentMenu = [...menus].reverse().find(isVisibleMenu);
29753
- if ((currentMenu === void 0 ? activeMenuKind : isWorkspaceFilterMenu(currentMenu) ? "filter" : "workspace") === "filter") injectFilterMenuAction(dom, selectFilterMenus(menus, menuWorkspaceIds, activeMenuWorkspaceId), showHiddenWorkspaces, () => {
29928
+ const currentMenuKind = currentMenu === void 0 ? activeMenuKind : isWorkspaceFilterMenu(currentMenu) ? "filter" : "workspace";
29929
+ const filterContextFresh = menuContextFresh && activeMenuKind === "filter";
29930
+ const filterMenus = currentMenuKind === "filter" ? selectFilterMenus(menus, menuWorkspaceIds, activeMenuWorkspaceId, filterContextFresh) : [];
29931
+ const currentMenuOwnsFilterAction = currentMenu !== void 0 && currentMenu.querySelector(`[data-codingns-hidden-workspace-filter]`) !== null;
29932
+ if (currentMenuKind === "filter" && (filterContextFresh || currentMenuOwnsFilterAction)) injectFilterMenuAction(dom, filterMenus, showHiddenWorkspaces, () => {
29754
29933
  showHiddenWorkspaces = !showHiddenWorkspaces;
29755
29934
  scheduleScan();
29756
29935
  }, (menu) => closeFilterMenu(activeFilterTrigger, menu, () => {
@@ -29759,7 +29938,7 @@ window.__ModuleLoader__.load({
29759
29938
  suppressFilterTrigger = false;
29760
29939
  };
29761
29940
  }), t);
29762
- else injectWorkspaceMenuActions(selectWorkspaceMenus(menus), dom, activeMenuWorkspaceId, workspaceIds, menuWorkspaceIds, (workspaceId) => updateVisibility(workspaceId, true), t);
29941
+ else injectWorkspaceMenuActions(selectWorkspaceMenus(menus, menuContextFresh, menuWorkspaceIds), dom, menuContextFresh ? activeMenuWorkspaceId : void 0, workspaceIds, menuWorkspaceIds, (workspaceId) => updateVisibility(workspaceId, true), t);
29763
29942
  if (menus.length === 0 && !menuContextPending) {
29764
29943
  activeMenuWorkspaceId = void 0;
29765
29944
  activeMenuKind = void 0;
@@ -29878,15 +30057,18 @@ window.__ModuleLoader__.load({
29878
30057
  * 菜单 Portal 在关闭时可能短暂保留旧节点。先过滤不可见节点,再按菜单内容
29879
30058
  * 区分筛选菜单和工作区操作菜单,避免旧筛选菜单抢走当前工作区菜单的注入目标。
29880
30059
  */
29881
- function selectFilterMenus(menus, menuWorkspaceIds, activeWorkspaceId) {
30060
+ function selectFilterMenus(menus, menuWorkspaceIds, activeWorkspaceId, allowUnidentified) {
29882
30061
  const visible = menus.filter(isVisibleMenu);
29883
30062
  const candidates = visible.filter(isWorkspaceFilterMenu);
29884
- if (candidates.length > 0) return [candidates[candidates.length - 1]];
30063
+ const owned = candidates.filter((menu) => menu.querySelector(`[${WORKSPACE_SESSION_HIDDEN_FILTER_ATTRIBUTE}]`) !== null);
30064
+ if (owned.length > 0) return [owned[owned.length - 1]];
30065
+ if (allowUnidentified && candidates.length > 0) return [candidates[candidates.length - 1]];
30066
+ if (!allowUnidentified) return [];
29885
30067
  const fallback = visible.filter((menu) => menuWorkspaceIds.get(menu) === void 0 && (activeWorkspaceId === void 0 || resolveWorkspaceId(menu) !== activeWorkspaceId) && menu.querySelector(`[data-codingns-hidden-workspace-menu]`) === null);
29886
30068
  return fallback.length > 0 ? [fallback[fallback.length - 1]] : [];
29887
30069
  }
29888
- function selectWorkspaceMenus(menus) {
29889
- const candidates = menus.filter(isVisibleMenu).filter((menu) => !isWorkspaceFilterMenu(menu));
30070
+ function selectWorkspaceMenus(menus, allowUnidentified, menuWorkspaceIds) {
30071
+ const candidates = menus.filter(isVisibleMenu).filter((menu) => !isWorkspaceFilterMenu(menu) && (allowUnidentified || resolveWorkspaceId(menu) !== void 0 || menuWorkspaceIds.get(menu) !== void 0));
29890
30072
  return candidates.length > 0 ? [candidates[candidates.length - 1]] : [];
29891
30073
  }
29892
30074
  function isVisibleMenu(menu) {
@@ -33151,7 +33333,8 @@ window.__ModuleLoader__.load({
33151
33333
  adapterId: next.adapterId,
33152
33334
  ...next.modelId ? { modelId: next.modelId } : {},
33153
33335
  ...next.effortId ? { effortId: next.effortId } : {},
33154
- ...next.serviceTierId ? { serviceTierId: next.serviceTierId } : {}
33336
+ ...next.serviceTierId ? { serviceTierId: next.serviceTierId } : {},
33337
+ ...next.translationEnabled === void 0 ? {} : { translationEnabled: next.translationEnabled }
33155
33338
  };
33156
33339
  selections.set(sessionId, normalized);
33157
33340
  selectionLastUsed.set(sessionId, Date.now());
@@ -33519,6 +33702,7 @@ window.__ModuleLoader__.load({
33519
33702
  adapterId,
33520
33703
  modelId: model.id,
33521
33704
  effortId: effort ?? "default",
33705
+ translationEnabled: currentSelection.translationEnabled === true,
33522
33706
  ...tier ? { serviceTierId: tier } : {}
33523
33707
  });
33524
33708
  };
@@ -33568,6 +33752,7 @@ window.__ModuleLoader__.load({
33568
33752
  adapterId: selection.adapterId,
33569
33753
  modelId: next.id,
33570
33754
  effortId: nextEffort ?? "default",
33755
+ translationEnabled: selection.translationEnabled === true,
33571
33756
  ...nextTier ? { serviceTierId: nextTier } : {}
33572
33757
  });
33573
33758
  setOpen(false);
@@ -33580,6 +33765,7 @@ window.__ModuleLoader__.load({
33580
33765
  adapterId: selection.adapterId,
33581
33766
  modelId: model.id,
33582
33767
  effortId: effort,
33768
+ translationEnabled: selection.translationEnabled === true,
33583
33769
  ...tier ? { serviceTierId: tier } : {}
33584
33770
  });
33585
33771
  setOpen(false);
@@ -33596,7 +33782,19 @@ window.__ModuleLoader__.load({
33596
33782
  adapterId: selection.adapterId,
33597
33783
  modelId: model.id,
33598
33784
  ...selection.effortId ? { effortId: selection.effortId } : {},
33599
- serviceTierId
33785
+ serviceTierId,
33786
+ translationEnabled: selection.translationEnabled === true
33787
+ });
33788
+ };
33789
+ const translationAvailable = require_session_translation.isSessionTranslationAdapter(selection.adapterId);
33790
+ const toggleTranslation = (next) => {
33791
+ if (model === void 0) return;
33792
+ update({
33793
+ adapterId: selection.adapterId,
33794
+ modelId: model.id,
33795
+ ...selection.effortId ? { effortId: selection.effortId } : {},
33796
+ ...selection.serviceTierId ? { serviceTierId: selection.serviceTierId } : {},
33797
+ translationEnabled: next
33600
33798
  });
33601
33799
  };
33602
33800
  const menu = loading ? [(0, react.createElement)("div", {
@@ -33609,6 +33807,15 @@ window.__ModuleLoader__.load({
33609
33807
  "aria-hidden": true,
33610
33808
  style: modelSpinnerStyle
33611
33809
  }), (0, react.createElement)("span", void 0, t("cli.loadingModel")))] : pane === "root" ? [
33810
+ ...translationAvailable ? [(0, react.createElement)("div", {
33811
+ key: "translation",
33812
+ className: "codingns4dsh-translation-toggle",
33813
+ style: serviceTierRowStyle
33814
+ }, (0, react.createElement)("span", { style: serviceTierLabelStyle }, t("cli.translationConversation")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
33815
+ checked: selection.translationEnabled === true,
33816
+ onChange: toggleTranslation,
33817
+ label: t("cli.translationConversationToggle")
33818
+ }))] : [],
33612
33819
  ...serviceTierAvailable ? [(0, react.createElement)("div", {
33613
33820
  key: "service-tier",
33614
33821
  className: "codingns4dsh-service-tier",
@@ -33800,6 +34007,7 @@ window.__ModuleLoader__.load({
33800
34007
  padding: "0 10px",
33801
34008
  display: "flex",
33802
34009
  alignItems: "center",
34010
+ justifyContent: "space-between",
33803
34011
  gap: 8,
33804
34012
  fontSize: require_theme.uiFontSize(14),
33805
34013
  lineHeight: "22px"
@@ -39014,10 +39222,10 @@ ${scope} [data-dockkit-strip-tabs] {
39014
39222
  }));
39015
39223
  }
39016
39224
  function readSessionIds(value) {
39017
- const record = asRecord$5(value);
39225
+ const record = asRecord$6(value);
39018
39226
  if (record === void 0) return [];
39019
39227
  const result = /* @__PURE__ */ new Set();
39020
- const byId = asRecord$5(record.byId);
39228
+ const byId = asRecord$6(record.byId);
39021
39229
  if (byId !== void 0) {
39022
39230
  for (const sessionId of Object.keys(byId)) if (sessionId.trim() !== "") result.add(sessionId);
39023
39231
  }
@@ -39033,7 +39241,7 @@ ${scope} [data-dockkit-strip-tabs] {
39033
39241
  const items = record[key];
39034
39242
  if (!Array.isArray(items)) continue;
39035
39243
  for (const item of items) {
39036
- const itemRecord = asRecord$5(item);
39244
+ const itemRecord = asRecord$6(item);
39037
39245
  const candidate = itemRecord?.sessionId ?? itemRecord?.id;
39038
39246
  if (typeof candidate === "string" && candidate.trim() !== "") result.add(candidate);
39039
39247
  }
@@ -39074,10 +39282,10 @@ ${scope} [data-dockkit-strip-tabs] {
39074
39282
  const iterator = (await api.follow())[Symbol.asyncIterator]();
39075
39283
  const first = await iterator.next();
39076
39284
  await iterator.return?.();
39077
- const unwrapped = asRecord$5(unwrapRemoteValue(first.value));
39078
- const value = Array.isArray(unwrapped?.items) ? unwrapped : asRecord$5(unwrapped?.value);
39285
+ const unwrapped = asRecord$6(unwrapRemoteValue(first.value));
39286
+ const value = Array.isArray(unwrapped?.items) ? unwrapped : asRecord$6(unwrapped?.value);
39079
39287
  return (Array.isArray(value?.items) ? value.items : []).flatMap((item) => {
39080
- const record = asRecord$5(item);
39288
+ const record = asRecord$6(item);
39081
39289
  const workspaceId = record?.workspaceId;
39082
39290
  if (typeof workspaceId !== "string" || workspaceId.trim() === "") return [];
39083
39291
  const rawSessionIds = record?.sessionIds;
@@ -39091,16 +39299,16 @@ ${scope} [data-dockkit-strip-tabs] {
39091
39299
  });
39092
39300
  }
39093
39301
  async function readCurrentSession(api, sessionId, uiContext) {
39094
- const store = asRecord$5(require_native_workspace_store.readNativeService(uiContext, "sessions", "list"));
39302
+ const store = asRecord$6(require_native_workspace_store.readNativeService(uiContext, "sessions", "list"));
39095
39303
  if (typeof store?.getSnapshot === "function") {
39096
- const snapshot = asRecord$5(store.getSnapshot());
39097
- const byId = asRecord$5(snapshot?.byId);
39098
- if (byId !== void 0) return sessionItem(asRecord$5(byId[sessionId]));
39099
- return sessionItem(asRecord$5((Array.isArray(snapshot?.items) ? snapshot.items : []).find((item) => asRecord$5(item)?.sessionId === sessionId)));
39304
+ const snapshot = asRecord$6(store.getSnapshot());
39305
+ const byId = asRecord$6(snapshot?.byId);
39306
+ if (byId !== void 0) return sessionItem(asRecord$6(byId[sessionId]));
39307
+ return sessionItem(asRecord$6((Array.isArray(snapshot?.items) ? snapshot.items : []).find((item) => asRecord$6(item)?.sessionId === sessionId)));
39100
39308
  }
39101
39309
  if (api?.list === void 0) return void 0;
39102
39310
  const result = await readLegacySessionList(api);
39103
- return sessionItem(asRecord$5((Array.isArray(result?.items) ? result.items : []).find((item) => asRecord$5(item)?.sessionId === sessionId)));
39311
+ return sessionItem(asRecord$6((Array.isArray(result?.items) ? result.items : []).find((item) => asRecord$6(item)?.sessionId === sessionId)));
39104
39312
  }
39105
39313
  function sessionItem(session) {
39106
39314
  if (session === void 0) return void 0;
@@ -39115,7 +39323,7 @@ ${scope} [data-dockkit-strip-tabs] {
39115
39323
  async function readLegacySessionList(api) {
39116
39324
  const previous = legacySessionLists.get(api);
39117
39325
  if (previous !== void 0 && Date.now() < previous.expiresAt) return previous.promise;
39118
- const promise = Promise.resolve().then(() => api.list({})).then((value) => asRecord$5(unwrapRemoteValue(value)));
39326
+ const promise = Promise.resolve().then(() => api.list({})).then((value) => asRecord$6(unwrapRemoteValue(value)));
39119
39327
  const entry = {
39120
39328
  promise,
39121
39329
  expiresAt: Infinity
@@ -39139,11 +39347,11 @@ ${scope} [data-dockkit-strip-tabs] {
39139
39347
  const result = value.replaceAll("\\", "/").replace(/\/+/u, "/").replace(/\/+$/u, "") || "/";
39140
39348
  return /^[A-Za-z]:\//u.test(result) ? result.toLowerCase() : result;
39141
39349
  }
39142
- function asRecord$5(value) {
39350
+ function asRecord$6(value) {
39143
39351
  return typeof value === "object" && value !== null ? value : void 0;
39144
39352
  }
39145
39353
  function unwrapRemoteValue(value) {
39146
- const record = asRecord$5(value);
39354
+ const record = asRecord$6(value);
39147
39355
  if (record === void 0 || typeof record.ok !== "boolean") return value;
39148
39356
  return record.ok ? record.value : void 0;
39149
39357
  }
@@ -40880,7 +41088,7 @@ ${scope} [data-dockkit-strip-tabs] {
40880
41088
  function registerSessionChangedFilesView(ctx, rpc, remote, locale) {
40881
41089
  const runtime = globalThis;
40882
41090
  if (runtime.__CODINGNS4DSH_SESSION_CHANGED_FILES_VIEW__ !== void 0) return void 0;
40883
- const slots = asRecord$4(ctx)?.slots;
41091
+ const slots = asRecord$5(ctx)?.slots;
40884
41092
  if (typeof slots?.inject !== "function" || typeof slots.register !== "function") return void 0;
40885
41093
  if (isSlotIdRegistered(slots, "conversation.view", "codingns4dsh/session-changed-files")) return void 0;
40886
41094
  if (isSlotIdRegistered(slots, "conversation.session.header.actions", `codingns4dsh/session-changed-files/counter`)) return void 0;
@@ -41195,7 +41403,7 @@ ${scope} [data-dockkit-strip-tabs] {
41195
41403
  function fileIcon(name) {
41196
41404
  return name.includes(".") ? "·" : "□";
41197
41405
  }
41198
- function asRecord$4(value) {
41406
+ function asRecord$5(value) {
41199
41407
  return typeof value === "object" && value !== null ? value : void 0;
41200
41408
  }
41201
41409
  async function call(rpc, endpoint, payload) {
@@ -41524,8 +41732,39 @@ ${scope} [data-dockkit-strip-tabs] {
41524
41732
  },
41525
41733
  settingsPanel: FileManagementPanel
41526
41734
  };
41735
+ //#endregion
41736
+ //#region src/client/settings-anchor.ts
41737
+ /**
41738
+ * 设置区锚点解析。
41739
+ *
41740
+ * 账户入口(登录/注销、PeerHost 管理)是命令式挂到 DSH 侧栏底部的,必须先找到
41741
+ * 一个稳定的落点。历史上只认原生齿轮按钮 `button[aria-label="设置"]`,它在
41742
+ * DSH Desktop 下**根本不会渲染**:
41743
+ *
41744
+ * 1. Desktop 的 preload 无条件暴露 `dshDesktop`
41745
+ * (`exposeInMainWorld("dshDesktop", …)`),
41746
+ * 2. `@deepseek-ai/dsh-client-ui-settings-account` 的 `apply` 见到该全局就注册
41747
+ * `settings.launcher` 单槽位(账户菜单),
41748
+ * 3. `@deepseek-ai/dsh-client-ui-settings-general` 渲染
41749
+ * `renderSlot("settings.launcher", …, { fallback: 齿轮按钮 })`,
41750
+ * 而单槽位一旦有条目就只渲染条目,fallback 不进入 DOM。
41751
+ *
41752
+ * 结果就是入口锚点为空、`scan()` 直接返回,左下角既没有账户图标也进不去
41753
+ * PeerHost 管理。这里把槽位出口 `[data-slot="settings.launcher"]` 作为兜底锚点:
41754
+ * 它由 DSH 槽位契约提供(`dsh-client-ui-renderer` 的 `SlotOutlet` 始终输出
41755
+ * `data-slot="<slotKey>"`,渲染 fallback 时也输出),与具体按钮实现无关,
41756
+ * 因此 Web 与 Desktop 都成立。
41757
+ */
41758
+ /**
41759
+ * 原生设置齿轮按钮;Web 浏览器下 `settings.launcher` 无条目,由它作为 fallback 渲染。
41760
+ *
41761
+ * DSH 的 `aria-label` 来自 locale 词典(`dsh-client-ui-settings-general` 的 `trigger`
41762
+ * 键:zh 为「设置」、en 为 `Settings`),因此选择器必须同时覆盖 DSH 0.2.0-rc.2 支持
41763
+ * 的两种语言,不能把中文标签当作唯一的语言无关契约。其它语言走槽位出口兜底。
41764
+ */
41765
+ const SETTINGS_BUTTON_SELECTOR = "button[aria-label=\"设置\"], button[aria-label=\"Settings\"]";
41527
41766
  /** 锚点候选按优先级排列:原生齿轮优先,槽位出口兜底。 */
41528
- const SETTINGS_ANCHOR_SELECTORS = ["button[aria-label=\"设置\"], button[aria-label=\"Settings\"]", "[data-slot=\"settings.launcher\"]"];
41767
+ const SETTINGS_ANCHOR_SELECTORS = [SETTINGS_BUTTON_SELECTOR, "[data-slot=\"settings.launcher\"]"];
41529
41768
  /**
41530
41769
  * 按优先级挑选设置区锚点。
41531
41770
  *
@@ -41642,17 +41881,18 @@ ${scope} [data-dockkit-strip-tabs] {
41642
41881
  observeDom = true;
41643
41882
  return;
41644
41883
  }
41645
- const match = resolveSettingsAnchor((selector) => root.querySelector(selector));
41646
- if (match === null) {
41647
- observeDom = true;
41648
- return;
41649
- }
41650
- const container = settingsAnchorContainer(match);
41884
+ const existing = root.querySelector(`button[${ACCOUNT_ATTRIBUTE}]`);
41885
+ let match = existing?.parentElement === null || existing?.parentElement === void 0 ? null : matchForAccountContainer(existing.parentElement);
41886
+ let container = match === null ? null : settingsAnchorContainer(match);
41651
41887
  if (container === null) {
41888
+ match = resolveSettingsAnchor((selector) => root.querySelector(selector));
41889
+ container = match === null ? null : settingsAnchorContainer(match);
41890
+ }
41891
+ if (match === null || container === null) {
41652
41892
  observeDom = true;
41653
41893
  return;
41654
41894
  }
41655
- let button = container.querySelector(`button[${ACCOUNT_ATTRIBUTE}]`);
41895
+ let button = existing ?? container.querySelector(`button[${ACCOUNT_ATTRIBUTE}]`);
41656
41896
  if (button === null) {
41657
41897
  button = createAccountButton(root, isDesktopPage());
41658
41898
  button.addEventListener("click", (event) => {
@@ -41661,8 +41901,13 @@ ${scope} [data-dockkit-strip-tabs] {
41661
41901
  toggleMenu(button);
41662
41902
  });
41663
41903
  }
41664
- if (match.kind === "launcher-slot") container.append(button);
41665
- else if (button.parentElement !== container) container.insertBefore(button, container.firstChild);
41904
+ if (button.parentElement !== container) {
41905
+ if (match.kind === "launcher-slot") container.append(button);
41906
+ else container.insertBefore(button, container.firstChild);
41907
+ }
41908
+ root.querySelectorAll(`button[${ACCOUNT_ATTRIBUTE}]`).forEach((node) => {
41909
+ if (node !== button) node.remove();
41910
+ });
41666
41911
  observeDom = false;
41667
41912
  observer?.disconnect();
41668
41913
  container.dataset.codingnsAccountRow = "true";
@@ -41679,12 +41924,9 @@ ${scope} [data-dockkit-strip-tabs] {
41679
41924
  };
41680
41925
  const updateAccountLayout = (container, anchor, button, kind) => {
41681
41926
  if (kind === "launcher-slot") {
41682
- const row = container.parentElement;
41683
- if (row === null) return;
41684
41927
  const mode = "desktop";
41685
41928
  if (button.dataset.codingnsWide === mode) return;
41686
41929
  button.dataset.codingnsWide = mode;
41687
- row.style.flexWrap = "nowrap";
41688
41930
  button.style.order = "2";
41689
41931
  button.style.marginLeft = "auto";
41690
41932
  return;
@@ -41726,9 +41968,8 @@ ${scope} [data-dockkit-strip-tabs] {
41726
41968
  };
41727
41969
  const observerCallback = () => {
41728
41970
  if (disposed || rendering || renderQueued) return;
41729
- const match = resolveSettingsAnchor((selector) => root.querySelector(selector));
41730
41971
  const button = root.querySelector(`button[${ACCOUNT_ATTRIBUTE}]`);
41731
- if (match !== null && button !== null && settingsAnchorContainer(match) === button.parentElement) return;
41972
+ if (button !== null && button.parentElement !== null && matchForAccountContainer(button.parentElement) !== null) return;
41732
41973
  renderQueued = true;
41733
41974
  queueMicrotask(() => {
41734
41975
  renderQueued = false;
@@ -42185,6 +42426,17 @@ ${scope} [data-dockkit-strip-tabs] {
42185
42426
  function isWide(parent, settings) {
42186
42427
  return parent.clientWidth > 96 || getComputedStyle(settings).display !== "none" && settings.getBoundingClientRect().width > 70;
42187
42428
  }
42429
+ function matchForAccountContainer(container) {
42430
+ if (container.matches("[data-slot=\"settings.launcher\"]")) return {
42431
+ kind: "launcher-slot",
42432
+ node: container
42433
+ };
42434
+ const settings = container.querySelector(SETTINGS_BUTTON_SELECTOR);
42435
+ return settings === null || settings.parentElement !== container ? null : {
42436
+ kind: "settings-button",
42437
+ node: settings
42438
+ };
42439
+ }
42188
42440
  function formatPercent(value) {
42189
42441
  return `${Math.round(value)}%`;
42190
42442
  }
@@ -43196,6 +43448,7 @@ ${scope} [data-dockkit-strip-tabs] {
43196
43448
  "codingnsTerminal/shells",
43197
43449
  "codingnsTerminal/write",
43198
43450
  "codingnsAssistantNotifications/sourceStream",
43451
+ "fileUploads/upload",
43199
43452
  "fileReferences/list",
43200
43453
  "skills/list"
43201
43454
  ]);
@@ -43564,12 +43817,12 @@ ${scope} [data-dockkit-strip-tabs] {
43564
43817
  const refreshStates = /* @__PURE__ */ new WeakMap();
43565
43818
  /** 合并并按 Host 侧顺序排列工作区;快照形状不符时原样返回,注入失败不影响本机数据。 */
43566
43819
  function mergeWorkspaceSnapshot(snapshot, virtual, orderedWorkspaceIds, localHostId, hasAggregate) {
43567
- const record = asRecord$3(snapshot);
43820
+ const record = asRecord$4(snapshot);
43568
43821
  if (record === null || !Array.isArray(record.items)) return snapshot;
43569
43822
  const baseItems = record.items;
43570
43823
  const byId = new Map(virtual.map((workspace) => [workspace.workspaceId, workspace]));
43571
43824
  const items = hasAggregate ? baseItems.flatMap((item) => {
43572
- const workspace = asRecord$3(item);
43825
+ const workspace = asRecord$4(item);
43573
43826
  const id = workspace?.workspaceId;
43574
43827
  const ref = typeof id === "string" ? require_primitives_adapter.parseVirtualWorkspaceId(id) : null;
43575
43828
  if (ref === null || ref.hostId === localHostId || ref.targetHostId === null) return [item];
@@ -43580,7 +43833,7 @@ ${scope} [data-dockkit-strip-tabs] {
43580
43833
  }];
43581
43834
  }) : baseItems;
43582
43835
  const known = new Set(items.flatMap((item) => {
43583
- const workspaceId = asRecord$3(item)?.workspaceId;
43836
+ const workspaceId = asRecord$4(item)?.workspaceId;
43584
43837
  if (typeof workspaceId !== "string") return [];
43585
43838
  const normalized = normalizeWorkspaceId(workspaceId, localHostId);
43586
43839
  return normalized === workspaceId ? [workspaceId] : [workspaceId, normalized];
@@ -43599,7 +43852,7 @@ ${scope} [data-dockkit-strip-tabs] {
43599
43852
  function normalizeRemoteWorkspaceDisplayPaths(items) {
43600
43853
  let changed = false;
43601
43854
  const normalized = items.map((item) => {
43602
- const record = asRecord$3(item);
43855
+ const record = asRecord$4(item);
43603
43856
  const workspaceId = record?.workspaceId;
43604
43857
  if (record === null || typeof workspaceId !== "string" || require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) === null) return item;
43605
43858
  const displayPath = createPeerHostWorkspaceDisplayPath(workspaceId);
@@ -43656,18 +43909,18 @@ ${scope} [data-dockkit-strip-tabs] {
43656
43909
  };
43657
43910
  }
43658
43911
  function mergeBlankSessionCwds(snapshot, workspaceSnapshot) {
43659
- const state = asRecord$3(snapshot);
43912
+ const state = asRecord$4(snapshot);
43660
43913
  const byId = state?.byId;
43661
- const workspaceState = asRecord$3(workspaceSnapshot);
43914
+ const workspaceState = asRecord$4(workspaceSnapshot);
43662
43915
  const items = Array.isArray(workspaceState?.items) ? workspaceState.items : [];
43663
43916
  if (state === null || !isRecord$4(byId) || items.length === 0) return snapshot;
43664
43917
  let changed = false;
43665
43918
  const nextById = { ...byId };
43666
43919
  for (const [id, value] of Object.entries(byId)) {
43667
- const session = asRecord$3(value);
43920
+ const session = asRecord$4(value);
43668
43921
  if (session === null || session.blank !== true) continue;
43669
- const displayPath = asRecord$3(items.find((item) => {
43670
- const record = asRecord$3(item);
43922
+ const displayPath = asRecord$4(items.find((item) => {
43923
+ const record = asRecord$4(item);
43671
43924
  return Array.isArray(record?.sessionIds) && record.sessionIds.includes(id);
43672
43925
  }))?.path;
43673
43926
  if (typeof displayPath !== "string" || displayPath === "" || session.cwd === displayPath) continue;
@@ -43760,18 +44013,18 @@ ${scope} [data-dockkit-strip-tabs] {
43760
44013
  function orderWorkspaceItems(items, orderedWorkspaceIds, localHostId) {
43761
44014
  if (orderedWorkspaceIds.length === 0 || items.length < 2) return items;
43762
44015
  if (localHostId === void 0 && items.some((item) => {
43763
- const workspaceId = asRecord$3(item)?.workspaceId;
44016
+ const workspaceId = asRecord$4(item)?.workspaceId;
43764
44017
  return typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) === null;
43765
44018
  })) return items;
43766
44019
  const hasLocalItem = localHostId !== void 0 && items.some((item) => {
43767
- const workspaceId = asRecord$3(item)?.workspaceId;
44020
+ const workspaceId = asRecord$4(item)?.workspaceId;
43768
44021
  return typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) === null;
43769
44022
  });
43770
44023
  const hasLocalOrder = localHostId !== void 0 && orderedWorkspaceIds.some((id) => require_primitives_adapter.parseVirtualWorkspaceId(id)?.hostId === localHostId);
43771
44024
  if (hasLocalItem && !hasLocalOrder) return items;
43772
44025
  const ranks = new Map(orderedWorkspaceIds.map((id, index) => [id, index]));
43773
44026
  const entries = items.map((item, index) => {
43774
- const workspaceId = asRecord$3(item)?.workspaceId;
44027
+ const workspaceId = asRecord$4(item)?.workspaceId;
43775
44028
  return {
43776
44029
  item,
43777
44030
  index,
@@ -43809,7 +44062,7 @@ ${scope} [data-dockkit-strip-tabs] {
43809
44062
  }
43810
44063
  return merged.length === original.length && merged.every((id, index) => id === original[index]) ? void 0 : merged;
43811
44064
  }
43812
- function asRecord$3(value) {
44065
+ function asRecord$4(value) {
43813
44066
  return isRecord$4(value) ? value : null;
43814
44067
  }
43815
44068
  function isRecord$4(value) {
@@ -44924,110 +45177,6 @@ ${scope} [data-dockkit-strip-tabs] {
44924
45177
  });
44925
45178
  }
44926
45179
  //#endregion
44927
- //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.1-alpha.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
44928
- /**
44929
- * The `dsh-resource://file/…` address grammar: how a file is named across the
44930
- * Sidebar and the resource model, built and parsed without touching a
44931
- * filesystem.
44932
- * @module
44933
- */
44934
- /** The scheme and type every file address opens with. */
44935
- const FILE_ADDRESS_PREFIX = "dsh-resource://file/";
44936
- /** Component-encode one id or path segment, keeping `:` literal for drive letters. */
44937
- function encodeSegment(segment) {
44938
- return encodeURIComponent(segment).replace(/%3A/gi, ":");
44939
- }
44940
- /** Encode a `/`-separated path segment by segment. */
44941
- function encodePath(path) {
44942
- return path.split("/").map(encodeSegment).join("/");
44943
- }
44944
- /** Whether a decoded first path segment is a Windows drive (`C:`). */
44945
- function isDriveSegment(segment) {
44946
- return segment !== void 0 && /^[A-Za-z]:$/.test(segment);
44947
- }
44948
- /**
44949
- * Build the address of a file read through one Session.
44950
- * @param sessionId - the Session whose Host workspace resolves the path.
44951
- * @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
44952
- * @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
44953
- */
44954
- function sessionFileAddress(sessionId, path) {
44955
- const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
44956
- return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
44957
- }
44958
- /**
44959
- * Read a file address back into its parts without resolving `.` or `..`.
44960
- * Query and fragment suffixes are ignored; encoded path segments are decoded.
44961
- * @param address - a candidate address.
44962
- * @returns the parts, or `undefined` when the string is not a `dsh-resource://file/` URI in a known scope with a path, or a segment is not validly encoded.
44963
- */
44964
- function parseFileAddress(address) {
44965
- try {
44966
- if (!address.startsWith(FILE_ADDRESS_PREFIX)) return void 0;
44967
- const end = address.search(/[?#]/);
44968
- const [scope, ...rest] = address.slice(20, end === -1 ? void 0 : end).split("/");
44969
- if (scope === "session") {
44970
- const [id, ...segments] = rest;
44971
- if (id === void 0 || id === "" || segments.length === 0) return void 0;
44972
- return {
44973
- scope,
44974
- sessionId: decodeURIComponent(id),
44975
- path: segments.map(decodeURIComponent).join("/")
44976
- };
44977
- }
44978
- if (scope === "absolute") {
44979
- const unc = rest[0] === "" && rest.length > 1;
44980
- const segments = (unc ? rest.slice(1) : rest).map(decodeURIComponent);
44981
- if (segments.length === 0 || segments[0] === "") return void 0;
44982
- if (unc) return {
44983
- scope,
44984
- path: `//${segments.join("/")}`
44985
- };
44986
- return {
44987
- scope,
44988
- path: isDriveSegment(segments[0]) ? segments.join("/") : `/${segments.join("/")}`
44989
- };
44990
- }
44991
- return;
44992
- } catch {
44993
- return;
44994
- }
44995
- }
44996
- //#endregion
44997
- //#region src/client/peer-host-file-links.ts
44998
- /**
44999
- * 在原生资源入口规范远端链接,保留资源里的虚拟会话身份和导航参数。
45000
- * 右栏文件树、消息与预览内链接共用这个入口;不扫描消息正文或当前选择。
45001
- */
45002
- function installPeerHostFileLinkRouting(uiContext, workspacePathForSession) {
45003
- const sidebar = uiContext.get("sidebarRight");
45004
- if (typeof sidebar?.openResource !== "function") return void 0;
45005
- const originalOpen = sidebar.openResource;
45006
- const originalOpenIn = sidebar.openResourceIn;
45007
- const resolve = (address, options) => {
45008
- const file = parseFileAddress(address);
45009
- if (file?.scope !== "session") return [address, options];
45010
- const location = normalizePeerHostFileLocation(file.path, workspacePathForSession(file.sessionId));
45011
- if (location.path === file.path) return [address, options];
45012
- const suffix = address.search(/[?#]/u);
45013
- return [sessionFileAddress(file.sessionId, location.path) + (suffix < 0 ? "" : address.slice(suffix)), location.line === void 0 ? options : {
45014
- ...options,
45015
- params: {
45016
- line: location.line,
45017
- ...options?.params
45018
- }
45019
- }];
45020
- };
45021
- const open = (address, options) => originalOpen.call(sidebar, ...resolve(address, options));
45022
- const openIn = originalOpenIn === void 0 ? void 0 : (sessionId, address, options) => originalOpenIn.call(sidebar, sessionId, ...resolve(address, options));
45023
- sidebar.openResource = open;
45024
- if (openIn !== void 0) sidebar.openResourceIn = openIn;
45025
- return () => {
45026
- if (sidebar.openResource === open) sidebar.openResource = originalOpen;
45027
- if (openIn !== void 0 && sidebar.openResourceIn === openIn) sidebar.openResourceIn = originalOpenIn;
45028
- };
45029
- }
45030
- //#endregion
45031
45180
  //#region src/shared/session-reference.ts
45032
45181
  /**
45033
45182
  * 生成 DSH 原生会话引用使用的 canonical URI。
@@ -45134,15 +45283,15 @@ ${scope} [data-dockkit-strip-tabs] {
45134
45283
  async function readRemoteCandidates(value) {
45135
45284
  const result = await value;
45136
45285
  if (Array.isArray(result)) return result.flatMap(asRemoteCandidate);
45137
- const record = asRecord$2(result);
45286
+ const record = asRecord$3(result);
45138
45287
  if (record?.ok === true && Array.isArray(record.value)) return record.value.flatMap(asRemoteCandidate);
45139
- const nested = asRecord$2(record?.ok === true ? record.value : void 0);
45288
+ const nested = asRecord$3(record?.ok === true ? record.value : void 0);
45140
45289
  if (Array.isArray(nested?.candidates)) return nested.candidates.flatMap(asRemoteCandidate);
45141
45290
  if (Array.isArray(record?.candidates)) return record.candidates.flatMap(asRemoteCandidate);
45142
45291
  return [];
45143
45292
  }
45144
45293
  function asRemoteCandidate(value) {
45145
- const record = asRecord$2(value);
45294
+ const record = asRecord$3(value);
45146
45295
  if (record === null || typeof record.sessionId !== "string" || typeof record.mention !== "string" || typeof record.label !== "string") return [];
45147
45296
  return [{
45148
45297
  sessionId: record.sessionId,
@@ -45176,14 +45325,14 @@ ${scope} [data-dockkit-strip-tabs] {
45176
45325
  value: formatSessionReferenceMention(title, session.sessionId)
45177
45326
  };
45178
45327
  }
45179
- function asRecord$2(value) {
45328
+ function asRecord$3(value) {
45180
45329
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
45181
45330
  }
45182
45331
  function readSelectedRemoteHost(service, sessionId) {
45183
45332
  const selection = service?.selection?.getSnapshot();
45184
- const record = asRecord$2(selection);
45333
+ const record = asRecord$3(selection);
45185
45334
  if (record === null) return void 0;
45186
- const selectedSessionId = typeof record.sessionId === "string" ? record.sessionId : asRecord$2(record.subagentAddress)?.parentSessionId;
45335
+ const selectedSessionId = typeof record.sessionId === "string" ? record.sessionId : asRecord$3(record.subagentAddress)?.parentSessionId;
45187
45336
  if (selectedSessionId !== void 0 && selectedSessionId !== sessionId) return void 0;
45188
45337
  const workspaceId = record.workspaceId;
45189
45338
  if (typeof workspaceId !== "string") return void 0;
@@ -45286,10 +45435,6 @@ ${scope} [data-dockkit-strip-tabs] {
45286
45435
  scope.effect(() => transport.watchNavigation(), "codingns4dsh: PeerHost model catalog navigation");
45287
45436
  });
45288
45437
  if (navigation !== void 0) context.resources.add(() => navigation.dispose());
45289
- const fileLinks = context.services.uiContext?.inject(["sidebarRight"], (scope) => {
45290
- scope.effect(() => installPeerHostFileLinkRouting(scope, (sessionId) => projection.sessions().find((session) => session.sessionId === sessionId)?.cwd) ?? (() => void 0), "codingns4dsh: PeerHost file links");
45291
- });
45292
- if (fileLinks !== void 0) context.resources.add(() => fileLinks.dispose());
45293
45438
  if (shim.getMode?.() === "desktop") reconnectNativeEvents(context.services.uiContext);
45294
45439
  }
45295
45440
  const panel = startPeerHostManagementPanel({
@@ -45428,9 +45573,9 @@ ${scope} [data-dockkit-strip-tabs] {
45428
45573
  return (await readPageRpcResponse(response)).result;
45429
45574
  };
45430
45575
  const codingNsCall = async (endpoint, payload, signal) => {
45431
- const result = asRecord$1(await request("/codingns", endpoint, payload, signal));
45576
+ const result = asRecord$2(await request("/codingns", endpoint, payload, signal));
45432
45577
  if (result?.ok === true) return result.value;
45433
- const error = asRecord$1(result?.error);
45578
+ const error = asRecord$2(result?.error);
45434
45579
  const failure = new Error(typeof error?.message === "string" ? error.message : `CodingNS RPC 失败: ${endpoint}`);
45435
45580
  if (typeof error?.code === "string") failure.code = error.code;
45436
45581
  throw failure;
@@ -45443,6 +45588,17 @@ ${scope} [data-dockkit-strip-tabs] {
45443
45588
  const scope = scopes.get(virtualSessionId);
45444
45589
  return scope?.targetHostId === parsed.hostId ? scope : void 0;
45445
45590
  };
45591
+ const scopeForFileUpload = (url) => {
45592
+ const virtualSessionId = url.searchParams.get("sessionId");
45593
+ if (virtualSessionId === null) return void 0;
45594
+ const parsed = require_primitives_adapter.parseVirtualSessionId(virtualSessionId);
45595
+ if (parsed === null) return void 0;
45596
+ const scope = scopes.get(virtualSessionId);
45597
+ return scope?.targetHostId === parsed.hostId && scope.sessionId === parsed.sessionId ? {
45598
+ virtualSessionId,
45599
+ scope
45600
+ } : void 0;
45601
+ };
45446
45602
  const sessionExportPath = (url, scope) => {
45447
45603
  const parsed = require_primitives_adapter.parseVirtualSessionId(url.searchParams.get("sessionId") ?? "");
45448
45604
  if (parsed === null || scope.targetHostId !== parsed.hostId) throw new Error("远程 Session 导出作用域不匹配");
@@ -45454,16 +45610,64 @@ ${scope} [data-dockkit-strip-tabs] {
45454
45610
  const raw = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
45455
45611
  return new URL(raw, typeof document === "undefined" ? "http://codingns.invalid" : document.baseURI);
45456
45612
  };
45613
+ const remoteFileUploadFetch = async (url, request, init, virtualSessionId, scope) => {
45614
+ const signal = init?.signal ?? request?.signal;
45615
+ signal?.throwIfAborted();
45616
+ const bodyRequest = new Request(request ?? url.href, init);
45617
+ const bytes = new Uint8Array(await bodyRequest.arrayBuffer());
45618
+ const name = url.searchParams.get("name");
45619
+ const payload = { args: {
45620
+ agentId: virtualSessionId,
45621
+ request: {
45622
+ data: encodeUploadBytesBase64(bytes),
45623
+ ...name === null ? {} : { name }
45624
+ }
45625
+ } };
45626
+ try {
45627
+ return jsonResponse({
45628
+ ok: true,
45629
+ value: decodeNativeResponseBytes(await codingNsCall("peerHost/native", {
45630
+ method: "fileUploads/upload",
45631
+ payload,
45632
+ scope
45633
+ }, signal))
45634
+ });
45635
+ } catch (error) {
45636
+ signal?.throwIfAborted();
45637
+ const code = error.code;
45638
+ return jsonResponse({
45639
+ ok: false,
45640
+ error: {
45641
+ code: typeof code === "string" ? code : "gateway/internal",
45642
+ message: error instanceof Error ? error.message : String(error),
45643
+ details: {}
45644
+ }
45645
+ });
45646
+ }
45647
+ };
45457
45648
  const remoteSessionExportFetch = async (input, init) => {
45458
45649
  if (fetchImpl === void 0) throw new Error("当前页面没有 fetch");
45459
45650
  const request = typeof Request !== "undefined" && input instanceof Request ? input : void 0;
45460
45651
  const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
45461
45652
  const url = readFetchUrl(input);
45653
+ if (url.pathname === "/api/session/uploadFileBinary" && method === "POST") {
45654
+ const parsed = require_primitives_adapter.parseVirtualSessionId(url.searchParams.get("sessionId") ?? "");
45655
+ const uploadScope = scopeForFileUpload(url);
45656
+ if (uploadScope !== void 0 && uploadScope.scope.targetHostId !== null) return remoteFileUploadFetch(url, request, init, uploadScope.virtualSessionId, uploadScope.scope);
45657
+ if (parsed !== null) return jsonResponse({
45658
+ ok: false,
45659
+ error: {
45660
+ code: "PEER_HOST_SCOPE_MISMATCH",
45661
+ message: t("peerHost.sessionUnavailable"),
45662
+ details: {}
45663
+ }
45664
+ }, 409);
45665
+ }
45462
45666
  if (url.pathname !== "/api/session.export" || method !== "GET" && method !== "HEAD") return fetchImpl(input, init);
45463
45667
  const scope = scopeForSessionExport(url);
45464
45668
  if (scope === void 0 || scope.targetHostId === null) return fetchImpl(input, init);
45465
45669
  const headers = init?.headers === void 0 && request === void 0 ? void 0 : Object.fromEntries(new Headers(init?.headers ?? request?.headers).entries());
45466
- const response = asRecord$1(await codingNsCall("peerHost/request", {
45670
+ const response = asRecord$2(await codingNsCall("peerHost/request", {
45467
45671
  peerHostId: scope.targetHostId,
45468
45672
  scope,
45469
45673
  path: sessionExportPath(url, scope),
@@ -45495,7 +45699,7 @@ ${scope} [data-dockkit-strip-tabs] {
45495
45699
  }
45496
45700
  return;
45497
45701
  }
45498
- const object = asRecord$1(value);
45702
+ const object = asRecord$2(value);
45499
45703
  if (object === null) return void 0;
45500
45704
  for (const item of Object.values(object)) {
45501
45705
  const found = findScope(item);
@@ -45505,8 +45709,8 @@ ${scope} [data-dockkit-strip-tabs] {
45505
45709
  const scopeForNativeRequest = (method, value) => {
45506
45710
  if (method === "userQuestions/answer" || method === "userQuestions/attachWait") return findScope(questionAgentId(value));
45507
45711
  if (method.startsWith("messageFeedback/") || method === "sessionFeedback/record") {
45508
- const input = asRecord$1(value);
45509
- const request = asRecord$1(asRecord$1(input?.args)?.request ?? input?.request);
45712
+ const input = asRecord$2(value);
45713
+ const request = asRecord$2(asRecord$2(input?.args)?.request ?? input?.request);
45510
45714
  return findScope(request?.sessionId);
45511
45715
  }
45512
45716
  const direct = findScope(value);
@@ -45514,9 +45718,9 @@ ${scope} [data-dockkit-strip-tabs] {
45514
45718
  return method === "session/modelCatalog" && !containsResourceId(value) ? navigationScope() : void 0;
45515
45719
  };
45516
45720
  const scopeForPluginRequest = (endpoint, value) => {
45517
- if ((endpoint === "cli/catalog" || endpoint === "cli/models" || endpoint === "cli/catalog/refresh") && asRecord$1(value)?.catalogHostId === "local") return void 0;
45721
+ if ((endpoint === "cli/catalog" || endpoint === "cli/models" || endpoint === "cli/catalog/refresh") && asRecord$2(value)?.catalogHostId === "local") return void 0;
45518
45722
  if (endpoint.startsWith("fileManagement/")) {
45519
- const input = asRecord$1(value);
45723
+ const input = asRecord$2(value);
45520
45724
  const workspace = findScope(input?.workspaceId);
45521
45725
  const session = findScope(input?.sessionId);
45522
45726
  if (hasVirtualResourceScope(value)) {
@@ -45527,7 +45731,7 @@ ${scope} [data-dockkit-strip-tabs] {
45527
45731
  return workspace ?? session;
45528
45732
  }
45529
45733
  if (isDebugPluginEndpoint(endpoint)) {
45530
- const input = asRecord$1(value);
45734
+ const input = asRecord$2(value);
45531
45735
  return findScope(input?.workspaceId) ?? findScope(input?.sessionId);
45532
45736
  }
45533
45737
  const direct = findScope(value);
@@ -45540,8 +45744,8 @@ ${scope} [data-dockkit-strip-tabs] {
45540
45744
  if (selection !== void 0) {
45541
45745
  const direct = findScope(selection);
45542
45746
  if (direct !== void 0) return direct;
45543
- const selected = asRecord$1(selection);
45544
- const sessionId = selected?.sessionId ?? asRecord$1(selected?.subagentAddress)?.parentSessionId;
45747
+ const selected = asRecord$2(selection);
45748
+ const sessionId = selected?.sessionId ?? asRecord$2(selected?.subagentAddress)?.parentSessionId;
45545
45749
  const session = typeof sessionId === "string" ? require_primitives_adapter.parseVirtualSessionId(sessionId) : null;
45546
45750
  const workspace = typeof selected?.workspaceId === "string" ? require_primitives_adapter.parseVirtualWorkspaceId(selected.workspaceId) : null;
45547
45751
  const hostId = session?.hostId ?? workspace?.targetHostId;
@@ -45565,7 +45769,7 @@ ${scope} [data-dockkit-strip-tabs] {
45565
45769
  };
45566
45770
  const containsResourceId = (value) => {
45567
45771
  if (Array.isArray(value)) return value.some(containsResourceId);
45568
- const record = asRecord$1(value);
45772
+ const record = asRecord$2(value);
45569
45773
  if (record === null) return false;
45570
45774
  for (const [key, child] of Object.entries(record)) {
45571
45775
  if ((key === "workspaceId" || key === "sessionId" || key === "parentSessionId") && typeof child === "string" && child !== "") return true;
@@ -45577,14 +45781,14 @@ ${scope} [data-dockkit-strip-tabs] {
45577
45781
  const containsVirtualResourceId = (value) => {
45578
45782
  if (typeof value === "string") return require_primitives_adapter.parseVirtualSessionId(value) !== null || require_primitives_adapter.parseVirtualWorkspaceId(value) !== null;
45579
45783
  if (Array.isArray(value)) return value.some(containsVirtualResourceId);
45580
- const record = asRecord$1(value);
45784
+ const record = asRecord$2(value);
45581
45785
  return record !== null && Object.values(record).some(containsVirtualResourceId);
45582
45786
  };
45583
45787
  const hasUnresolvedVirtualNativeScope = (method, value) => {
45584
45788
  if (method === "userQuestions/answer" || method === "userQuestions/attachWait") return false;
45585
45789
  if (method.startsWith("messageFeedback/") || method === "sessionFeedback/record") {
45586
- const input = asRecord$1(value);
45587
- const request = asRecord$1(asRecord$1(input?.args)?.request ?? input?.request);
45790
+ const input = asRecord$2(value);
45791
+ const request = asRecord$2(asRecord$2(input?.args)?.request ?? input?.request);
45588
45792
  return typeof request?.sessionId === "string" && require_primitives_adapter.parseVirtualSessionId(request.sessionId) !== null;
45589
45793
  }
45590
45794
  return containsVirtualResourceId(value);
@@ -45595,13 +45799,13 @@ ${scope} [data-dockkit-strip-tabs] {
45595
45799
  return (key === "sessionId" || key === "parentSessionId" || key === "childSessionId") && parsed !== null && parsed.hostId === (scope.targetHostId ?? scope.hostId) ? parsed.sessionId : value;
45596
45800
  }
45597
45801
  if (Array.isArray(value)) return value.map((item) => rewriteCliPayload(item, scope, key));
45598
- const record = asRecord$1(value);
45802
+ const record = asRecord$2(value);
45599
45803
  if (record === null) return value;
45600
45804
  return Object.fromEntries(Object.entries(record).map(([childKey, child]) => [childKey, rewriteCliPayload(child, scope, childKey)]));
45601
45805
  };
45602
45806
  const remotePluginRpc = async (scope, endpoint, payload, signal) => {
45603
45807
  if (scope.targetHostId === null) throw new Error("PeerHost 插件请求缺少目标 Host");
45604
- const response = asRecord$1(await codingNsCall("peerHost/request", {
45808
+ const response = asRecord$2(await codingNsCall("peerHost/request", {
45605
45809
  peerHostId: scope.targetHostId,
45606
45810
  scope,
45607
45811
  path: `/api/codingns/${endpoint}`,
@@ -45610,7 +45814,7 @@ ${scope} [data-dockkit-strip-tabs] {
45610
45814
  rpcId: createRequestId(),
45611
45815
  method: endpoint,
45612
45816
  payload: endpoint.startsWith("git/") ? {
45613
- ...asRecord$1(payload),
45817
+ ...asRecord$2(payload),
45614
45818
  workspaceId: scope.workspaceId
45615
45819
  } : endpoint.startsWith("cli/") ? rewriteCliPayload(payload, scope) : rewritePluginResourcePayload(payload, scope)
45616
45820
  })
@@ -45620,7 +45824,7 @@ ${scope} [data-dockkit-strip-tabs] {
45620
45824
  if (status < 200 || status >= 300) {
45621
45825
  let error = null;
45622
45826
  try {
45623
- error = asRecord$1(asRecord$1(JSON.parse(body))?.error);
45827
+ error = asRecord$2(asRecord$2(JSON.parse(body))?.error);
45624
45828
  } catch {}
45625
45829
  if (typeof error?.code === "string" && typeof error.message === "string") return {
45626
45830
  ok: false,
@@ -45632,21 +45836,21 @@ ${scope} [data-dockkit-strip-tabs] {
45632
45836
  throw new Error(`远端 Host 插件 RPC 失败: HTTP ${status}`);
45633
45837
  }
45634
45838
  try {
45635
- const envelope = asRecord$1(JSON.parse(body));
45839
+ const envelope = asRecord$2(JSON.parse(body));
45636
45840
  return endpoint.startsWith("git/") ? projectGitWorkspaceIds(envelope?.result, scope.workspaceId, require_primitives_adapter.createVirtualWorkspaceId(scope.targetHostId, scope.workspaceId)) : envelope?.result;
45637
45841
  } catch {
45638
45842
  throw new Error("远端 Host 插件 RPC 响应不是 JSON");
45639
45843
  }
45640
45844
  };
45641
45845
  const mergeRemoteAdapterMap = async (localResult, signal) => {
45642
- const localEnvelope = asRecord$1(localResult);
45846
+ const localEnvelope = asRecord$2(localResult);
45643
45847
  if (localEnvelope?.ok !== true || !Array.isArray(localEnvelope.value)) return localResult;
45644
45848
  const rows = [...localEnvelope.value];
45645
45849
  for (const [targetHostId, scope] of remoteHostScopes) try {
45646
- const remoteEnvelope = asRecord$1(await remotePluginRpc(scope, "cli/session/adapter-map", {}, signal));
45850
+ const remoteEnvelope = asRecord$2(await remotePluginRpc(scope, "cli/session/adapter-map", {}, signal));
45647
45851
  if (remoteEnvelope?.ok !== true || !Array.isArray(remoteEnvelope.value)) continue;
45648
45852
  for (const raw of remoteEnvelope.value) {
45649
- const row = asRecord$1(raw);
45853
+ const row = asRecord$2(raw);
45650
45854
  const sessionId = typeof row?.sessionId === "string" ? row.sessionId : "";
45651
45855
  const adapterId = typeof row?.adapterId === "string" ? row.adapterId : "";
45652
45856
  if (sessionId !== "" && adapterId !== "") rows.push({
@@ -45661,7 +45865,7 @@ ${scope} [data-dockkit-strip-tabs] {
45661
45865
  };
45662
45866
  };
45663
45867
  const openRemoteStream = (method, payload, scope, signal) => (async function* () {
45664
- const opened = asRecord$1(await codingNsCall("peerHost/nativeStream", {
45868
+ const opened = asRecord$2(await codingNsCall("peerHost/nativeStream", {
45665
45869
  method,
45666
45870
  payload,
45667
45871
  scope
@@ -45670,7 +45874,7 @@ ${scope} [data-dockkit-strip-tabs] {
45670
45874
  if (streamId === "") throw new Error("PeerHost 原生 Remote 未返回 streamId");
45671
45875
  try {
45672
45876
  while (!(signal?.aborted ?? false)) {
45673
- const next = asRecord$1(await codingNsCall("peerHost/nativeStreamNext", {
45877
+ const next = asRecord$2(await codingNsCall("peerHost/nativeStreamNext", {
45674
45878
  streamId,
45675
45879
  scope
45676
45880
  }, signal));
@@ -45695,7 +45899,7 @@ ${scope} [data-dockkit-strip-tabs] {
45695
45899
  }, signal),
45696
45900
  accepts: (agentId, scope) => scopes.get(agentId)?.targetHostId === scope.targetHostId,
45697
45901
  onSessionStatus: (sessionId, running) => {
45698
- if (projection.setSessionRunning(sessionId, running)) refreshPeerHostNativeSessions(uiContext);
45902
+ projection.setSessionRunning(sessionId, running);
45699
45903
  },
45700
45904
  prepare: async () => {
45701
45905
  if (nativeSessionPrepared) return;
@@ -45712,7 +45916,7 @@ ${scope} [data-dockkit-strip-tabs] {
45712
45916
  return pending;
45713
45917
  };
45714
45918
  const rememberCreatedSession = (scope, value) => {
45715
- const sessionId = asRecord$1(value)?.sessionId;
45919
+ const sessionId = asRecord$2(value)?.sessionId;
45716
45920
  if (typeof sessionId !== "string") return;
45717
45921
  const parsed = require_primitives_adapter.parseVirtualSessionId(sessionId);
45718
45922
  if (parsed === null) return;
@@ -45742,17 +45946,22 @@ ${scope} [data-dockkit-strip-tabs] {
45742
45946
  };
45743
45947
  /** 父会话目录早于聚合到达时,复用新建会话的临时作用域与清理机制。 */
45744
45948
  const rememberSubagentCatalog = (scope, value) => {
45745
- const catalog = asRecord$1(asRecord$1(asRecord$1(value)?.projections)?.values)?.subagentCatalog;
45746
- if (!Array.isArray(catalog)) return;
45949
+ const catalog = asRecord$2(asRecord$2(asRecord$2(value)?.projections)?.values)?.subagentCatalog;
45950
+ if (!Array.isArray(catalog)) return false;
45951
+ let changed = false;
45747
45952
  for (const child of catalog) {
45748
- const id = asRecord$1(child)?.id;
45749
- if (typeof id === "string" && !scopes.has(id)) rememberCreatedSession(scope, { sessionId: id });
45953
+ const id = asRecord$2(child)?.id;
45954
+ if (typeof id === "string" && !scopes.has(id)) {
45955
+ rememberCreatedSession(scope, { sessionId: id });
45956
+ changed = true;
45957
+ }
45750
45958
  }
45959
+ return changed;
45751
45960
  };
45752
45961
  return {
45753
45962
  hooks: {
45754
45963
  rpc: async ({ method, payload, signal }) => {
45755
- const value = asRecord$1(payload);
45964
+ const value = asRecord$2(payload);
45756
45965
  const channel = typeof value?.channel === "string" ? value.channel : "/codingns";
45757
45966
  const body = value?.payload;
45758
45967
  if (channel === "/api" && method === "$events/result" && events.ownsResult(body)) try {
@@ -45787,7 +45996,7 @@ ${scope} [data-dockkit-strip-tabs] {
45787
45996
  message: t("peerHost.debugWorkspaceUnavailable")
45788
45997
  }
45789
45998
  };
45790
- const workspaceId = asRecord$1(body)?.workspaceId;
45999
+ const workspaceId = asRecord$2(body)?.workspaceId;
45791
46000
  const scope = endpoint.startsWith("git/") ? findScope(workspaceId) : scopeForPluginRequest(endpoint, body);
45792
46001
  if (endpoint.startsWith("git/") && typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) !== null && scope === void 0) return {
45793
46002
  ok: false,
@@ -45862,7 +46071,7 @@ ${scope} [data-dockkit-strip-tabs] {
45862
46071
  return result;
45863
46072
  },
45864
46073
  openStream: ({ method, payload, signal }) => {
45865
- const value = asRecord$1(payload);
46074
+ const value = asRecord$2(payload);
45866
46075
  const channel = typeof value?.channel === "string" ? value.channel : "/api";
45867
46076
  const body = value?.payload;
45868
46077
  if (channel === "/api" && method === "$events") return events.open((localSignal) => openDshGatewayStream(method, body, localSignal), signal);
@@ -45878,16 +46087,13 @@ ${scope} [data-dockkit-strip-tabs] {
45878
46087
  const stream = openRemoteStream(method, body, scope, signal);
45879
46088
  if (method !== "session/follow") return stream;
45880
46089
  return (async function* () {
45881
- let emitted = false;
45882
46090
  try {
45883
46091
  for await (const chunk of stream) {
45884
- emitted = true;
45885
- rememberSubagentCatalog(scope, chunk);
45886
- scheduleAggregateRefresh();
46092
+ if (rememberSubagentCatalog(scope, chunk)) scheduleAggregateRefresh();
45887
46093
  yield chunk;
45888
46094
  }
45889
46095
  } finally {
45890
- if (!emitted) scheduleAggregateRefresh();
46096
+ if (!(signal?.aborted ?? false)) scheduleAggregateRefresh();
45891
46097
  }
45892
46098
  })();
45893
46099
  }
@@ -45921,7 +46127,7 @@ ${scope} [data-dockkit-strip-tabs] {
45921
46127
  return scope === void 0 ? hasVirtualResourceScope(value) : scope.targetHostId !== null;
45922
46128
  }
45923
46129
  if (method?.startsWith("git/") || method?.startsWith("codingns/git/")) {
45924
- const workspaceId = asRecord$1(value)?.workspaceId;
46130
+ const workspaceId = asRecord$2(value)?.workspaceId;
45925
46131
  return typeof workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(workspaceId) !== null;
45926
46132
  }
45927
46133
  const cli = method === void 0 ? void 0 : method === "cli/catalog" || method === "cli/models" ? method : method.startsWith("codingns/cli/") ? method.slice(9) : void 0;
@@ -46013,8 +46219,8 @@ ${scope} [data-dockkit-strip-tabs] {
46013
46219
  return endpoint.startsWith("cli/") || endpoint.startsWith("git/") || endpoint.startsWith("debug/") || endpoint.startsWith("fileManagement/") || endpoint === "terminal/status" ? endpoint : void 0;
46014
46220
  }
46015
46221
  function questionAgentId(value) {
46016
- const input = asRecord$1(value);
46017
- return asRecord$1(input?.args)?.agentId ?? input?.agentId;
46222
+ const input = asRecord$2(value);
46223
+ return asRecord$2(input?.args)?.agentId ?? input?.agentId;
46018
46224
  }
46019
46225
  function hasVirtualQuestionAgent(method, value) {
46020
46226
  if (method !== "userQuestions/answer" && method !== "userQuestions/attachWait") return false;
@@ -46025,19 +46231,19 @@ ${scope} [data-dockkit-strip-tabs] {
46025
46231
  return endpoint.startsWith("debug/") || endpoint === "terminal/status";
46026
46232
  }
46027
46233
  function hasVirtualResourceScope(value) {
46028
- const input = asRecord$1(value);
46234
+ const input = asRecord$2(value);
46029
46235
  return typeof input?.workspaceId === "string" && require_primitives_adapter.parseVirtualWorkspaceId(input.workspaceId) !== null || typeof input?.sessionId === "string" && require_primitives_adapter.parseVirtualSessionId(input.sessionId) !== null;
46030
46236
  }
46031
46237
  /** 只投影响应中的工作区标识;Diff、提交正文和文件路径均保持原文。 */
46032
46238
  function projectGitWorkspaceIds(value, workspaceId, virtualWorkspaceId) {
46033
46239
  if (Array.isArray(value)) return value.map((item) => projectGitWorkspaceIds(item, workspaceId, virtualWorkspaceId));
46034
- const record = asRecord$1(value);
46240
+ const record = asRecord$2(value);
46035
46241
  if (record === null) return value;
46036
46242
  return Object.fromEntries(Object.entries(record).map(([key, child]) => [key, key === "workspaceId" && child === workspaceId ? virtualWorkspaceId : projectGitWorkspaceIds(child, workspaceId, virtualWorkspaceId)]));
46037
46243
  }
46038
46244
  /** 只还原调试与文件请求的顶层资源标识,配置、文件正文和路径必须原样保存。 */
46039
46245
  function rewritePluginResourcePayload(value, scope) {
46040
- const input = asRecord$1(value);
46246
+ const input = asRecord$2(value);
46041
46247
  if (input === null) return value;
46042
46248
  const result = { ...input };
46043
46249
  const workspace = typeof input.workspaceId === "string" ? require_primitives_adapter.parseVirtualWorkspaceId(input.workspaceId) : null;
@@ -46138,7 +46344,7 @@ ${scope} [data-dockkit-strip-tabs] {
46138
46344
  /** 只借用原生导航数据,不修改选择策略,也不从后台保留会话推断前台。 */
46139
46345
  function readNativeNavigationStore(uiContext) {
46140
46346
  try {
46141
- const store = asRecord$1(asRecord$1(uiContext?.get("uiWorkspace"))?.selection);
46347
+ const store = asRecord$2(asRecord$2(uiContext?.get("uiWorkspace"))?.selection);
46142
46348
  if (typeof store?.getSnapshot !== "function" || typeof store.subscribe !== "function") return void 0;
46143
46349
  return store;
46144
46350
  } catch {
@@ -46147,14 +46353,14 @@ ${scope} [data-dockkit-strip-tabs] {
46147
46353
  }
46148
46354
  /** 把虚拟会话摘要并入 session/list 结果;形状不符时保持本机结果不变。 */
46149
46355
  function mergeSessionListResult(result, projection) {
46150
- const envelope = asRecord$1(result);
46356
+ const envelope = asRecord$2(result);
46151
46357
  if (envelope?.ok !== true) return result;
46152
- const value = asRecord$1(envelope.value);
46358
+ const value = asRecord$2(envelope.value);
46153
46359
  if (value === null || !Array.isArray(value.items)) return result;
46154
46360
  const virtual = projection.sessions();
46155
46361
  if (virtual.length === 0) return result;
46156
46362
  const known = new Set(value.items.flatMap((item) => {
46157
- const id = asRecord$1(item)?.sessionId;
46363
+ const id = asRecord$2(item)?.sessionId;
46158
46364
  return typeof id === "string" ? [id] : [];
46159
46365
  }));
46160
46366
  for (const session of virtual) if (session.adapterId !== void 0) publishSessionAdapter(session.sessionId, session.adapterId);
@@ -46170,7 +46376,7 @@ ${scope} [data-dockkit-strip-tabs] {
46170
46376
  function createRequestId() {
46171
46377
  return typeof globalThis.crypto?.randomUUID === "function" ? globalThis.crypto.randomUUID() : `${Date.now()}-${Math.random()}`;
46172
46378
  }
46173
- function asRecord$1(value) {
46379
+ function asRecord$2(value) {
46174
46380
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
46175
46381
  }
46176
46382
  /**
@@ -46189,8 +46395,8 @@ ${scope} [data-dockkit-strip-tabs] {
46189
46395
  }
46190
46396
  const metadata = fields.get("metadata");
46191
46397
  if (typeof metadata !== "string") throw new TypeError("connection: invalid binary response fields");
46192
- const envelope = asRecord$1(JSON.parse(metadata));
46193
- const result = asRecord$1(envelope?.result);
46398
+ const envelope = asRecord$2(JSON.parse(metadata));
46399
+ const result = asRecord$2(envelope?.result);
46194
46400
  if (envelope === null || result === null) throw new TypeError("connection: invalid server-response envelope");
46195
46401
  fields.delete("metadata");
46196
46402
  if (result.ok !== true) {
@@ -46201,7 +46407,7 @@ ${scope} [data-dockkit-strip-tabs] {
46201
46407
  if (!Array.isArray(attachments) || attachments.length === 0) throw new TypeError("connection: invalid binary response result");
46202
46408
  const root = { value: result.value };
46203
46409
  for (const rawAttachment of attachments) {
46204
- const attachment = asRecord$1(rawAttachment);
46410
+ const attachment = asRecord$2(rawAttachment);
46205
46411
  const path = attachment?.path;
46206
46412
  const part = attachment?.part;
46207
46413
  if (attachment?.codec !== "bytes" || typeof part !== "string" || !Array.isArray(path)) throw new TypeError("connection: invalid binary response attachment");
@@ -46246,8 +46452,8 @@ ${scope} [data-dockkit-strip-tabs] {
46246
46452
  function refreshDshModelCatalog(uiContext) {
46247
46453
  if (uiContext === void 0) return;
46248
46454
  try {
46249
- const service = asRecord$1(uiContext.get("modelDirectories"));
46250
- const catalog = service === null ? null : asRecord$1(service.catalog);
46455
+ const service = asRecord$2(uiContext.get("modelDirectories"));
46456
+ const catalog = service === null ? null : asRecord$2(service.catalog);
46251
46457
  if (catalog === null) return;
46252
46458
  const resetGeneration = catalog.resetGeneration;
46253
46459
  const refresh = catalog.refresh;
@@ -46429,6 +46635,20 @@ ${scope} [data-dockkit-strip-tabs] {
46429
46635
  for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
46430
46636
  return bytes.buffer;
46431
46637
  }
46638
+ function encodeUploadBytesBase64(bytes) {
46639
+ let binary = "";
46640
+ for (const byte of bytes) binary += String.fromCharCode(byte);
46641
+ if (typeof btoa === "function") return btoa(binary);
46642
+ const nodeBuffer = globalThis.Buffer;
46643
+ if (nodeBuffer !== void 0) return nodeBuffer.from(bytes).toString("base64");
46644
+ throw new Error("当前运行时不支持 Base64 编码");
46645
+ }
46646
+ function jsonResponse(value, status = 200) {
46647
+ return new Response(JSON.stringify(value), {
46648
+ status,
46649
+ headers: { "content-type": "application/json; charset=utf-8" }
46650
+ });
46651
+ }
46432
46652
  /** PeerHost 启用状态说明;安装动作发生在启动页 preboot 阶段。 */
46433
46653
  function PeerHostPanel({ services, enabled }) {
46434
46654
  const t = require_transport.useCodingNsTranslator(services.locale);
@@ -48259,16 +48479,17 @@ ${scope} [data-dockkit-strip-tabs] {
48259
48479
  function isPendingNotice(notice) {
48260
48480
  return (notice.kind === "question" || notice.kind === "approval") && notice.lifecycle === "active";
48261
48481
  }
48262
- function AssistantNotificationBubble({ frame, t, error, onOpen, onDismiss, onPresented, autoClose = false, autoCloseSeconds = 30, onExpandedChange, onClearAll, tailSide = "bottom", tailTarget, tailStyle }) {
48482
+ function AssistantNotificationBubble({ frame, t, error, onOpen, onDismiss, onAutoClose, onPresented, autoClose = false, autoCloseSeconds = 30, onExpandedChange, onCollapsedChange, onClearAll, onSizeChange, tailSide = "bottom", tailTarget, tailStyle }) {
48263
48483
  const [expanded, setExpanded] = (0, react.useState)(false);
48264
48484
  const [collapsed, setCollapsed] = (0, react.useState)(false);
48265
48485
  const [listFilter, setListFilter] = (0, react.useState)("all");
48266
48486
  const [processing, setProcessing] = (0, react.useState)(false);
48267
48487
  const bubble = (0, react.useRef)(null);
48488
+ const shellBox = (0, react.useRef)(null);
48268
48489
  const autoCloseTimer = (0, react.useRef)(void 0);
48269
48490
  const snapshot = "items" in frame ? frame : void 0;
48270
48491
  const primary = snapshot === void 0 ? frame : snapshot.primary;
48271
- const items = snapshot?.items.filter((notice) => !notice.read || isPendingNotice(notice)) ?? [];
48492
+ const items = snapshot === void 0 ? [] : [...snapshot.primary !== null && !snapshot.items.some((notice) => notice.noticeId === snapshot.primary.noticeId) ? [snapshot.primary] : [], ...snapshot.items];
48272
48493
  const attentionItems = snapshot === void 0 ? primary === void 0 || primary === null ? [] : [primary] : [...snapshot.primary === null || snapshot.primary.presentation === "collapsed" ? [] : [snapshot.primary], ...items.filter((notice) => notice.presentation !== "collapsed" && (!notice.read || isPendingNotice(notice)) && notice.noticeId !== snapshot.primary?.noticeId)];
48273
48494
  const multiple = attentionItems.length > 1 || snapshot !== void 0 && Math.max(snapshot.unreadCount, snapshot.pendingCount) > 1;
48274
48495
  const mainNotice = attentionItems[0] ?? (snapshot === void 0 ? primary ?? void 0 : void 0);
@@ -48283,6 +48504,13 @@ ${scope} [data-dockkit-strip-tabs] {
48283
48504
  (0, react.useEffect)(() => {
48284
48505
  setListFilter("all");
48285
48506
  }, [frame.generation, snapshot?.reset]);
48507
+ (0, react.useEffect)(() => {
48508
+ const node = shellBox.current;
48509
+ if (onSizeChange === void 0 || node === null || typeof ResizeObserver === "undefined") return;
48510
+ const observer = new ResizeObserver(() => onSizeChange(Math.ceil(node.getBoundingClientRect().height)));
48511
+ observer.observe(node);
48512
+ return () => observer.disconnect();
48513
+ }, [onSizeChange]);
48286
48514
  (0, react.useEffect)(() => {
48287
48515
  if (presented === void 0 || presented === null) return;
48288
48516
  const node = bubble.current;
@@ -48294,7 +48522,8 @@ ${scope} [data-dockkit-strip-tabs] {
48294
48522
  const connectionGeneration = "connectionGeneration" in presented ? presented.connectionGeneration : void 0;
48295
48523
  autoCloseTimer.current = setTimeout(() => {
48296
48524
  autoCloseTimer.current = void 0;
48297
- onDismiss(presented.noticeId, frame.generation, connectionGeneration);
48525
+ if (onAutoClose !== void 0) onAutoClose(presented.noticeId, frame.generation, connectionGeneration);
48526
+ else onDismiss(presented.noticeId, frame.generation, connectionGeneration);
48298
48527
  }, autoCloseSeconds * 1e3);
48299
48528
  };
48300
48529
  const confirm = () => {
@@ -48335,7 +48564,8 @@ ${scope} [data-dockkit-strip-tabs] {
48335
48564
  autoClose,
48336
48565
  autoCloseSeconds,
48337
48566
  onPresented,
48338
- onDismiss
48567
+ onDismiss,
48568
+ onAutoClose
48339
48569
  ]);
48340
48570
  const clearableCount = snapshot === void 0 ? 0 : [...snapshot.items, ...snapshot.primary === null ? [] : [snapshot.primary]].filter((notice) => !notice.read && !isPendingNotice(notice)).length;
48341
48571
  const showClearAll = snapshot !== void 0 && clearableCount > 0 && onClearAll !== void 0;
@@ -48344,7 +48574,7 @@ ${scope} [data-dockkit-strip-tabs] {
48344
48574
  const showExpandButton = collapsed && (mainNotice !== void 0 || hasNotificationCounts);
48345
48575
  const showTopRow = showCollapseButton || showExpandButton || showClearAll || hasNotificationCounts;
48346
48576
  const showBubble = !collapsed && (!expanded || snapshot === void 0) && mainNotice !== void 0;
48347
- const showFilterTags = snapshot !== void 0 && (multiple || collapsed);
48577
+ const showFilterTags = snapshot !== void 0 && hasNotificationCounts && (multiple || items.length > 1);
48348
48578
  const listItems = listFilter === "unread" ? items.filter((notice) => !notice.read && !isPendingNotice(notice)) : listFilter === "pending" ? items.filter((notice) => isPendingNotice(notice)) : items;
48349
48579
  const tail = tailSide !== "top" && (showBubble || expanded && snapshot !== void 0) ? (0, react.createElement)("span", {
48350
48580
  "aria-hidden": true,
@@ -48361,10 +48591,11 @@ ${scope} [data-dockkit-strip-tabs] {
48361
48591
  style: tailSvg(tailSide)
48362
48592
  }, (0, react.createElement)("path", {
48363
48593
  d: `${notificationTailCurve} Z`,
48364
- fill: require_theme.dshThemeColor.menuBackground
48594
+ fill: notificationTheme.surface
48365
48595
  }))) : null;
48366
48596
  const toggleFilter = (filter) => {
48367
48597
  setCollapsed(false);
48598
+ onCollapsedChange?.(false);
48368
48599
  setListFilter(listFilter === filter ? "all" : filter);
48369
48600
  setExpanded(true);
48370
48601
  };
@@ -48427,6 +48658,7 @@ ${scope} [data-dockkit-strip-tabs] {
48427
48658
  style: panel
48428
48659
  }, capability.reason)) ?? [];
48429
48660
  return (0, react.createElement)("div", {
48661
+ ref: shellBox,
48430
48662
  "data-codingns-assistant-notifications": true,
48431
48663
  style: shell,
48432
48664
  onPointerDown: (event) => event.stopPropagation(),
@@ -48441,8 +48673,10 @@ ${scope} [data-dockkit-strip-tabs] {
48441
48673
  "aria-label": t(collapsed ? "awb.notifications.expand" : "awb.notifications.collapse"),
48442
48674
  title: t(collapsed ? "awb.notifications.expand" : "awb.notifications.collapse"),
48443
48675
  onClick: () => {
48444
- setExpanded(false);
48445
- setCollapsed((value) => !value);
48676
+ const nextCollapsed = !collapsed;
48677
+ setCollapsed(nextCollapsed);
48678
+ setExpanded(!nextCollapsed);
48679
+ onCollapsedChange?.(nextCollapsed);
48446
48680
  }
48447
48681
  }, notificationToolbarIcon(collapsed ? "expand" : "collapse")) : null, !collapsed && showClearAll ? (0, react.createElement)("button", {
48448
48682
  type: "button",
@@ -48595,67 +48829,88 @@ ${scope} [data-dockkit-strip-tabs] {
48595
48829
  if (notice.kind === "question") return t("awb.notifications.question");
48596
48830
  return t("awb.notifications.approval");
48597
48831
  }
48832
+ /** 独立伴随页没有 DSH 主题变量,回退色固定为夜间灰;宿主页面仍可通过变量覆盖。 */
48833
+ const notificationTheme = {
48834
+ labelPrimary: "var(--dsw-alias-label-primary, #f1f2f4)",
48835
+ labelSecondary: "var(--dsw-alias-label-secondary, #b7bac1)",
48836
+ border: "var(--dsw-alias-border-l2, #5b5e66)",
48837
+ surface: "var(--dsw-alias-bg-layer-3, #303237)",
48838
+ card: "var(--dsw-alias-bg-layer-1, #3b3d43)",
48839
+ button: "var(--dsw-alias-button-elevated-fill, #44474e)",
48840
+ shadow: "var(--dsw-elevation-prominent, 0 12px 36px rgba(0, 0, 0, 0.42))"
48841
+ };
48598
48842
  const button = {
48599
48843
  ...require_theme.dshSettingsButtonStyle,
48600
48844
  minHeight: 36,
48601
48845
  touchAction: "manipulation",
48602
48846
  whiteSpace: "normal",
48603
48847
  borderRadius: 999,
48604
- fontWeight: 650
48848
+ fontWeight: 650,
48849
+ color: notificationTheme.labelPrimary,
48850
+ background: notificationTheme.button,
48851
+ borderColor: notificationTheme.border
48605
48852
  };
48853
+ /** 外壳按实际内容收缩,避免原生为形象预留的高度变成大片不透明背景。 */
48606
48854
  const shell = {
48607
48855
  position: "relative",
48608
48856
  isolation: "isolate",
48609
48857
  width: "100%",
48610
48858
  maxWidth: 320,
48611
- height: "100%",
48859
+ height: "auto",
48612
48860
  maxHeight: "var(--codingns-notification-max-height, min(276px, calc(100vh - 24px)))",
48613
48861
  minHeight: 0,
48614
48862
  display: "flex",
48615
48863
  flexDirection: "column",
48616
48864
  gap: 6,
48865
+ padding: 10,
48866
+ boxSizing: "border-box",
48617
48867
  pointerEvents: "auto",
48618
- color: require_theme.dshThemeColor.labelPrimary,
48619
- fontSize: require_theme.uiFontSize(13)
48868
+ color: notificationTheme.labelPrimary,
48869
+ fontSize: require_theme.uiFontSize(13),
48870
+ background: notificationTheme.surface,
48871
+ border: `1px solid ${notificationTheme.border}`,
48872
+ borderRadius: "24px 24px 24px 8px",
48873
+ boxShadow: notificationTheme.shadow
48620
48874
  };
48621
48875
  const panel = {
48622
48876
  position: "relative",
48623
48877
  zIndex: 1,
48624
48878
  padding: 10,
48625
- background: require_theme.dshThemeColor.menuBackground,
48626
- border: `1px solid ${require_theme.dshThemeColor.border}`,
48879
+ background: notificationTheme.surface,
48880
+ border: `1px solid ${notificationTheme.border}`,
48627
48881
  borderRadius: 18,
48628
- boxShadow: require_theme.dshThemeColor.prominentShadow,
48882
+ boxShadow: notificationTheme.shadow,
48629
48883
  minWidth: 0,
48630
48884
  boxSizing: "border-box",
48631
- maxHeight: "min(276px, calc(100vh - 24px))",
48885
+ maxHeight: "var(--codingns-notification-max-height, min(276px, calc(100vh - 24px)))",
48632
48886
  overflowY: "auto"
48633
48887
  };
48634
48888
  const bubblePanel = {
48635
- ...panel,
48636
48889
  position: "relative",
48637
48890
  display: "flex",
48638
48891
  flexDirection: "column",
48639
- flex: "1 1 auto",
48892
+ flex: "0 1 auto",
48640
48893
  minWidth: 0,
48641
48894
  minHeight: 0,
48642
- padding: 10,
48895
+ padding: 0,
48643
48896
  overflow: "visible",
48644
48897
  border: "none",
48645
- borderRadius: "24px 24px 24px 8px",
48646
- maxHeight: "100%",
48647
- background: require_theme.dshThemeColor.menuBackground,
48648
- borderColor: "transparent",
48898
+ borderRadius: 0,
48649
48899
  boxShadow: "none",
48900
+ maxHeight: "var(--codingns-notification-max-height, min(276px, calc(100vh - 24px)))",
48901
+ background: "transparent",
48650
48902
  outline: "none"
48651
48903
  };
48652
48904
  const bubbleContent = {
48653
48905
  position: "relative",
48654
48906
  zIndex: 1,
48655
48907
  display: "grid",
48908
+ gridAutoRows: "max-content",
48909
+ alignContent: "start",
48656
48910
  gap: 8,
48657
48911
  minHeight: 0,
48658
- flex: "1 1 auto",
48912
+ flex: "0 1 auto",
48913
+ maxHeight: "var(--codingns-notification-max-height, min(276px, calc(100vh - 24px)))",
48659
48914
  overflowY: "auto",
48660
48915
  overscrollBehavior: "contain",
48661
48916
  boxSizing: "border-box",
@@ -48722,7 +48977,7 @@ ${scope} [data-dockkit-strip-tabs] {
48722
48977
  transform: `translate(-50%, -50%) rotate(${side === "left" ? 90 : -90}deg)`
48723
48978
  };
48724
48979
  }
48725
- const notificationBubbleCss = "[data-codingns-notification-scroll]{scrollbar-width:none;-ms-overflow-style:none}[data-codingns-notification-scroll]::-webkit-scrollbar{display:none;width:0;height:0}[data-codingns-notification-filter], [data-codingns-notification-filter]:focus, [data-codingns-notification-filter]:focus-visible{border:1px solid var(--dsw-alias-border-l2,#d9d9d9)!important;outline:none!important;box-shadow:none!important}";
48980
+ const notificationBubbleCss = "[data-codingns-notification-scroll]{scrollbar-width:none;-ms-overflow-style:none}[data-codingns-notification-scroll]::-webkit-scrollbar{display:none;width:0;height:0}[data-codingns-notification-filter], [data-codingns-notification-filter]:focus, [data-codingns-notification-filter]:focus-visible{border:1px solid var(--dsw-alias-border-l2,#5b5e66)!important;outline:none!important;box-shadow:none!important}";
48726
48981
  const primaryCard = {
48727
48982
  display: "grid",
48728
48983
  gridTemplateColumns: "minmax(0, 1fr) auto",
@@ -48738,10 +48993,10 @@ ${scope} [data-dockkit-strip-tabs] {
48738
48993
  gap: 7,
48739
48994
  padding: "10px 11px",
48740
48995
  minWidth: 0,
48741
- background: require_theme.dshThemeColor.cardBackground,
48742
- border: `1px solid ${require_theme.dshThemeColor.border}`,
48996
+ background: notificationTheme.card,
48997
+ border: `1px solid ${notificationTheme.border}`,
48743
48998
  borderRadius: 15,
48744
- boxShadow: require_theme.dshThemeColor.subtleShadow
48999
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.24)"
48745
49000
  };
48746
49001
  const cardBody = {
48747
49002
  display: "grid",
@@ -48756,7 +49011,7 @@ ${scope} [data-dockkit-strip-tabs] {
48756
49011
  minWidth: 0
48757
49012
  };
48758
49013
  const cardMeta = {
48759
- color: require_theme.dshThemeColor.labelSecondary,
49014
+ color: notificationTheme.labelSecondary,
48760
49015
  fontSize: require_theme.uiFontSize(11),
48761
49016
  lineHeight: 1.3,
48762
49017
  overflowWrap: "anywhere"
@@ -48774,13 +49029,13 @@ ${scope} [data-dockkit-strip-tabs] {
48774
49029
  width: 24,
48775
49030
  height: 24,
48776
49031
  borderRadius: "50%",
48777
- color: require_theme.dshThemeColor.primaryForeground,
49032
+ color: "#fff",
48778
49033
  fontSize: require_theme.uiFontSize(13),
48779
49034
  fontWeight: 800,
48780
- boxShadow: require_theme.dshThemeColor.subtleShadow
49035
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.28)"
48781
49036
  };
48782
49037
  const messageText = {
48783
- color: require_theme.dshThemeColor.labelPrimary,
49038
+ color: notificationTheme.labelPrimary,
48784
49039
  whiteSpace: "pre-wrap",
48785
49040
  overflowWrap: "anywhere",
48786
49041
  lineHeight: 1.5,
@@ -48811,8 +49066,8 @@ ${scope} [data-dockkit-strip-tabs] {
48811
49066
  gap: 4,
48812
49067
  minWidth: 46,
48813
49068
  padding: "2px 7px",
48814
- background: require_theme.dshThemeColor.menuBackground,
48815
- boxShadow: require_theme.dshThemeColor.subtleShadow
49069
+ background: notificationTheme.button,
49070
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.24)"
48816
49071
  };
48817
49072
  const filterButtonActive = {
48818
49073
  ...filterButton,
@@ -48828,8 +49083,8 @@ ${scope} [data-dockkit-strip-tabs] {
48828
49083
  padding: "0 4px",
48829
49084
  boxSizing: "border-box",
48830
49085
  borderRadius: 8,
48831
- color: require_theme.dshThemeColor.labelPrimary,
48832
- background: require_theme.dshThemeColor.cardBackground,
49086
+ color: notificationTheme.labelPrimary,
49087
+ background: notificationTheme.card,
48833
49088
  fontSize: require_theme.uiFontSize(10),
48834
49089
  lineHeight: 1,
48835
49090
  fontWeight: 750
@@ -48841,18 +49096,19 @@ ${scope} [data-dockkit-strip-tabs] {
48841
49096
  };
48842
49097
  const topRow = {
48843
49098
  display: "flex",
49099
+ width: "100%",
48844
49100
  flexShrink: 0,
48845
49101
  alignItems: "center",
48846
49102
  justifyContent: "center",
48847
- flexWrap: "wrap",
49103
+ flexWrap: "nowrap",
48848
49104
  gap: 6
48849
49105
  };
48850
49106
  const clearAllButton = {
48851
49107
  ...toolbarIconButton,
48852
49108
  alignSelf: "end",
48853
- background: require_theme.dshThemeColor.buttonBackground,
48854
- borderColor: require_theme.dshThemeColor.border,
48855
- color: require_theme.dshThemeColor.labelPrimary,
49109
+ background: notificationTheme.button,
49110
+ borderColor: notificationTheme.border,
49111
+ color: notificationTheme.labelPrimary,
48856
49112
  borderRadius: 10,
48857
49113
  boxShadow: "none"
48858
49114
  };
@@ -48884,7 +49140,7 @@ ${scope} [data-dockkit-strip-tabs] {
48884
49140
  const compactPrompt = {
48885
49141
  fontSize: require_theme.uiFontSize(12),
48886
49142
  lineHeight: 1.4,
48887
- color: require_theme.dshThemeColor.labelPrimary
49143
+ color: notificationTheme.labelPrimary
48888
49144
  };
48889
49145
  const compactRequestTag = {
48890
49146
  ...requestInlineTag,
@@ -48902,7 +49158,7 @@ ${scope} [data-dockkit-strip-tabs] {
48902
49158
  color: require_theme.dshThemeColor.warningForeground
48903
49159
  };
48904
49160
  const compactStatus = {
48905
- color: require_theme.dshThemeColor.labelSecondary,
49161
+ color: notificationTheme.labelSecondary,
48906
49162
  fontSize: require_theme.uiFontSize(11),
48907
49163
  lineHeight: 1.3,
48908
49164
  paddingLeft: 32
@@ -49314,6 +49570,10 @@ ${scope} [data-dockkit-strip-tabs] {
49314
49570
  ...record.unchanged === void 0 ? {} : { unchanged: record.unchanged }
49315
49571
  };
49316
49572
  }
49573
+ /** 空快照只代表通知中心已经返回结果,不应被当成需要挂载气泡的通知。 */
49574
+ function assistantNotificationSnapshotHasNotifications(snapshot) {
49575
+ return snapshot.primary !== null || snapshot.unreadCount > 0 || snapshot.pendingCount > 0 || snapshot.capabilities.some((entry) => Boolean(entry.reason) && (!entry.completed || !entry.error || !entry.requests || !entry.resolve || !entry.navigation));
49576
+ }
49317
49577
  //#endregion
49318
49578
  //#region src/client/avatar/desktop-bridge.ts
49319
49579
  /** 普通浏览器即使连接到 Desktop 的 Host,也只能使用页面内形象。 */
@@ -49384,7 +49644,7 @@ ${scope} [data-dockkit-strip-tabs] {
49384
49644
  for (const event of status.noticeEvents) {
49385
49645
  if (disposed) return;
49386
49646
  if (event.ownerId !== ownerId || event.generation !== status.generation || !Number.isSafeInteger(event.sequence) || event.sequence <= (noticeAck?.sequence ?? 0) || typeof event.noticeId !== "string" || !Number.isSafeInteger(event.noticeGeneration)) continue;
49387
- const handler = event.type === "notice-presented" ? hooks.onNoticePresented : event.type === "notice-action" && (event.action === "open" || event.action === "dismiss" || event.action === "dismiss-all") ? hooks.onNoticeAction : void 0;
49647
+ const handler = event.type === "notice-presented" ? hooks.onNoticePresented : event.type === "notice-action" && (event.action === "open" || event.action === "collapse" || event.action === "dismiss" || event.action === "dismiss-all") ? hooks.onNoticeAction : void 0;
49388
49648
  if (!handler) break;
49389
49649
  try {
49390
49650
  await handler(event);
@@ -50009,11 +50269,11 @@ ${scope} [data-dockkit-strip-tabs] {
50009
50269
  }
50010
50270
  }
50011
50271
  /** 将本地/远端虚拟选择归一化为 Host 可匹配的会话三元组。 */
50012
- function normalizeAssistantSessionSelection(value) {
50013
- const record = asRecord(value);
50272
+ function normalizeAssistantSessionSelection(value, context) {
50273
+ const record = asRecord$1(value);
50014
50274
  if (record === void 0) return void 0;
50015
- const rawSessionId = text$1(record.sessionId) ?? text$1(asRecord(record.subagentAddress)?.parentSessionId);
50016
- const rawWorkspaceId = text$1(record.workspaceId);
50275
+ const rawSessionId = text$1(record.sessionId) ?? text$1(asRecord$1(record.subagentAddress)?.parentSessionId);
50276
+ const rawWorkspaceId = text$1(record.workspaceId) ?? text$1(asRecord$1(record.workspace)?.workspaceId) ?? (rawSessionId === void 0 ? void 0 : readSessionWorkspaceId(context, rawSessionId));
50017
50277
  if (rawSessionId === void 0 || rawWorkspaceId === void 0) return void 0;
50018
50278
  const session = require_primitives_adapter.parseVirtualSessionId(rawSessionId);
50019
50279
  const workspace = require_primitives_adapter.parseVirtualWorkspaceId(rawWorkspaceId);
@@ -50027,6 +50287,22 @@ ${scope} [data-dockkit-strip-tabs] {
50027
50287
  sessionId
50028
50288
  };
50029
50289
  }
50290
+ /** 从原生 Workspace 列表按成员关系反查当前会话,保留远端虚拟 ID。 */
50291
+ function readSessionWorkspaceId(context, sessionId) {
50292
+ try {
50293
+ const snapshot = require_native_workspace_store.readNativeWorkspaceSnapshot(context);
50294
+ const exact = snapshot?.items.find((workspace) => workspace.sessionIds.includes(sessionId));
50295
+ if (exact !== void 0) return exact.workspaceId;
50296
+ const parsed = require_primitives_adapter.parseVirtualSessionId(sessionId);
50297
+ if (parsed === null) return void 0;
50298
+ return (snapshot?.items.find((workspace) => workspace.sessionIds.some((candidate) => {
50299
+ const value = require_primitives_adapter.parseVirtualSessionId(candidate);
50300
+ return value?.hostId === parsed.hostId && value.sessionId === parsed.sessionId;
50301
+ })))?.workspaceId;
50302
+ } catch {
50303
+ return;
50304
+ }
50305
+ }
50030
50306
  /** Host 负责目标与连接代次校验,本适配器只把可信目标交给原生导航。 */
50031
50307
  async function openAssistantNotificationSession(services, target, signal) {
50032
50308
  signal?.throwIfAborted();
@@ -50063,7 +50339,7 @@ ${scope} [data-dockkit-strip-tabs] {
50063
50339
  return;
50064
50340
  }
50065
50341
  }
50066
- function asRecord(value) {
50342
+ function asRecord$1(value) {
50067
50343
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
50068
50344
  }
50069
50345
  function text$1(value) {
@@ -50203,7 +50479,7 @@ ${scope} [data-dockkit-strip-tabs] {
50203
50479
  const selection = readAssistantSessionSelectionStore(scope);
50204
50480
  if (selection === void 0) return void 0;
50205
50481
  const sync = () => {
50206
- notifications.markSessionRead(normalizeAssistantSessionSelection(selection.getSnapshot())).catch(() => void 0);
50482
+ notifications.markSessionRead(normalizeAssistantSessionSelection(selection.getSnapshot(), scope)).catch(() => void 0);
50207
50483
  };
50208
50484
  sync();
50209
50485
  return selection.subscribe(sync);
@@ -50226,6 +50502,9 @@ ${scope} [data-dockkit-strip-tabs] {
50226
50502
  const dismissNotice = (0, react.useCallback)((noticeId, generation, connectionGeneration) => {
50227
50503
  notifications.acknowledge(noticeId, generation, "dismiss", void 0, connectionGeneration).catch(() => void 0);
50228
50504
  }, [notifications]);
50505
+ const collapseNotice = (0, react.useCallback)((noticeId, generation, connectionGeneration) => {
50506
+ notifications.acknowledge(noticeId, generation, "collapse", void 0, connectionGeneration).catch(() => void 0);
50507
+ }, [notifications]);
50229
50508
  const openNotice = (0, react.useCallback)((noticeId, generation, connectionGeneration) => {
50230
50509
  notifications.open(noticeId, generation, connectionGeneration).catch(() => void 0);
50231
50510
  }, [notifications]);
@@ -50498,7 +50777,7 @@ ${scope} [data-dockkit-strip-tabs] {
50498
50777
  userText: partialText || liveUserText,
50499
50778
  assistantText: liveAssistantText
50500
50779
  } : void 0;
50501
- const noticeFrame = notificationsEnabled ? notificationSnapshot.frame : void 0;
50780
+ const noticeFrame = notificationsEnabled && notificationSnapshot.frame !== void 0 && assistantNotificationSnapshotHasNotifications(notificationSnapshot.frame) ? notificationSnapshot.frame : void 0;
50502
50781
  const reaction = assistantNotificationReaction(noticeFrame);
50503
50782
  const desktopNotification = desktopAssistantNotification(noticeFrame, notificationSnapshot.errorNoticeId === noticeFrame?.primary?.noticeId ? notificationSnapshot.error : void 0);
50504
50783
  const desktopNotificationSnapshot = readDesktopAssistantNotificationSnapshot(noticeFrame);
@@ -50517,7 +50796,8 @@ ${scope} [data-dockkit-strip-tabs] {
50517
50796
  onNoticeAction: async (event) => {
50518
50797
  await notifications.refresh(true);
50519
50798
  if (event.action === "dismiss-all") return notifications.clearAll(event.noticeGeneration);
50520
- return event.action === "open" ? notifications.open(event.noticeId, event.noticeGeneration, event.connectionGeneration) : notifications.acknowledge(event.noticeId, event.noticeGeneration, "dismiss", void 0, event.connectionGeneration);
50799
+ if (event.action === "open") return notifications.open(event.noticeId, event.noticeGeneration, event.connectionGeneration);
50800
+ return notifications.acknowledge(event.noticeId, event.noticeGeneration, event.action === "collapse" ? "collapse" : "dismiss", void 0, event.connectionGeneration);
50521
50801
  }
50522
50802
  });
50523
50803
  const nativeFloating = floatingEnabled && desktopAvatar.native;
@@ -50537,6 +50817,7 @@ ${scope} [data-dockkit-strip-tabs] {
50537
50817
  autoCloseSeconds: notificationSettings.autoCloseSeconds,
50538
50818
  onPresented: presentNotice,
50539
50819
  onDismiss: dismissNotice,
50820
+ onAutoClose: collapseNotice,
50540
50821
  onOpen: openNotice,
50541
50822
  onClearAll: clearAllNotices,
50542
50823
  tailSide: tail,
@@ -51689,6 +51970,928 @@ ${scope} [data-dockkit-strip-tabs] {
51689
51970
  }
51690
51971
  };
51691
51972
  //#endregion
51973
+ //#region src/client/session-translation-chat.ts
51974
+ /**
51975
+ * 把翻译状态和查看原文的入口放回对应消息块,不占用 AI 回复底部的统一操作栏。
51976
+ */
51977
+ function TranslationAction(props) {
51978
+ const source = props.record === void 0 ? readEventSource(props.services, props.sessionId) : void 0;
51979
+ const [, refresh] = (0, react.useState)(0);
51980
+ const [open, setOpen] = (0, react.useState)(false);
51981
+ const rootRef = (0, react.useRef)(null);
51982
+ const buttonRef = (0, react.useRef)(null);
51983
+ const popupRef = (0, react.useRef)(null);
51984
+ const [popupPosition, setPopupPosition] = (0, react.useState)(null);
51985
+ (0, react.useEffect)(() => {
51986
+ if (source === void 0) return void 0;
51987
+ return source.subscribe(() => refresh((value) => value + 1));
51988
+ }, [source]);
51989
+ useDismissOnOutsidePointer(rootRef, open, () => setOpen(false), { portal: popupRef });
51990
+ (0, react.useLayoutEffect)(() => {
51991
+ if (!open || typeof window === "undefined") {
51992
+ setPopupPosition(null);
51993
+ return;
51994
+ }
51995
+ const updatePosition = () => {
51996
+ const button = buttonRef.current;
51997
+ if (button === null) return;
51998
+ const rect = button.getBoundingClientRect();
51999
+ const edge = 12;
52000
+ const gap = 8;
52001
+ const width = Math.max(1, Math.min(420, window.innerWidth - 24));
52002
+ const availableAbove = Math.max(0, rect.top - gap - edge);
52003
+ const availableBelow = Math.max(0, window.innerHeight - rect.bottom - gap - edge);
52004
+ const preferredHeight = Math.min(440, window.innerHeight * .65);
52005
+ const placement = availableAbove >= preferredHeight || availableBelow < preferredHeight && availableAbove > availableBelow ? "above" : "below";
52006
+ const maxHeight = Math.min(preferredHeight, placement === "above" ? availableAbove : availableBelow);
52007
+ const desiredLeft = props.popupAlign === "end" ? rect.right - width : rect.left;
52008
+ const maxLeft = Math.max(edge, window.innerWidth - edge - width);
52009
+ setPopupPosition({
52010
+ left: Math.min(maxLeft, Math.max(edge, desiredLeft)),
52011
+ top: placement === "above" ? rect.top - gap : rect.bottom + gap,
52012
+ width,
52013
+ maxHeight,
52014
+ placement
52015
+ });
52016
+ };
52017
+ updatePosition();
52018
+ window.addEventListener("resize", updatePosition);
52019
+ window.addEventListener("scroll", updatePosition, true);
52020
+ return () => {
52021
+ window.removeEventListener("resize", updatePosition);
52022
+ window.removeEventListener("scroll", updatePosition, true);
52023
+ };
52024
+ }, [open, props.popupAlign]);
52025
+ const record = props.record ?? (source === void 0 || props.lookupText === void 0 ? void 0 : findTranslationRecordForText(source.getSnapshot(), props.lookupText, props.outputKind, props.turn, props.step));
52026
+ if (record === void 0) return null;
52027
+ const failed = record.failed === true;
52028
+ const alreadyTargetLanguage = record.alreadyTargetLanguage === true;
52029
+ const statusText = failed ? props.translationT("translation.statusFailed") : alreadyTargetLanguage ? props.translationT("translation.statusNotNeeded") : props.translationT("translation.statusTranslated");
52030
+ const model = formatModel(record.model, props.translationT);
52031
+ const detailsId = `codingns-translation-details-${safeDomId(props.messageId)}`;
52032
+ const details = open && popupPosition !== null ? (0, react.createElement)("div", {
52033
+ ref: popupRef,
52034
+ role: "dialog",
52035
+ "aria-label": props.translationT("translation.detailsTitle"),
52036
+ id: detailsId,
52037
+ style: {
52038
+ position: "fixed",
52039
+ zIndex: 2147483647,
52040
+ left: popupPosition.left,
52041
+ top: popupPosition.top,
52042
+ width: popupPosition.width,
52043
+ maxHeight: popupPosition.maxHeight,
52044
+ boxSizing: "border-box",
52045
+ ...popupPosition.placement === "above" ? { transform: "translateY(-100%)" } : {},
52046
+ overflow: "auto",
52047
+ padding: "10px 12px",
52048
+ border: `1px solid ${require_theme.dshThemeColor.border}`,
52049
+ borderRadius: 8,
52050
+ color: require_theme.dshThemeColor.labelPrimary,
52051
+ background: require_theme.dshThemeColor.menuBackground,
52052
+ boxShadow: "0 8px 24px color-mix(in srgb, CanvasText 16%, transparent)",
52053
+ fontSize: require_theme.uiFontSize(12),
52054
+ lineHeight: 1.45
52055
+ }
52056
+ }, (0, react.createElement)("div", { style: {
52057
+ display: "flex",
52058
+ justifyContent: "space-between",
52059
+ gap: 10,
52060
+ fontWeight: 600
52061
+ } }, (0, react.createElement)("span", void 0, props.translationT("translation.detailsTitle")), (0, react.createElement)("span", { style: {
52062
+ color: failed ? require_theme.dshThemeColor.error : alreadyTargetLanguage ? require_theme.dshThemeColor.accent : require_theme.dshThemeColor.success,
52063
+ fontWeight: 400
52064
+ } }, statusText)), record.sourceLanguage === void 0 ? null : (0, react.createElement)("div", { style: {
52065
+ marginTop: 8,
52066
+ color: require_theme.dshThemeColor.labelSecondary
52067
+ } }, `${props.translationT("translation.detectedLanguage")}: ${props.translationT(`translation.language.${record.sourceLanguage}`)}`), (0, react.createElement)(DetailBlock, {
52068
+ label: props.translationT("translation.originalText"),
52069
+ value: record.original
52070
+ }), (0, react.createElement)(DetailBlock, {
52071
+ label: props.translationT("translation.translatedText"),
52072
+ value: record.translated
52073
+ }), (0, react.createElement)("div", { style: {
52074
+ marginTop: 8,
52075
+ color: require_theme.dshThemeColor.labelSecondary
52076
+ } }, `${props.translationT("translation.modelUsed")}: ${alreadyTargetLanguage ? props.translationT("translation.modelNotUsed") : model}`)) : null;
52077
+ const renderedDetails = details === null ? null : typeof document === "undefined" ? details : (0, import_react_dom.createPortal)(details, document.body);
52078
+ return (0, react.createElement)("div", {
52079
+ ref: rootRef,
52080
+ style: {
52081
+ position: "relative",
52082
+ display: "inline-flex",
52083
+ alignItems: "center",
52084
+ verticalAlign: "middle",
52085
+ ...props.inline === true ? { marginInlineStart: 4 } : {}
52086
+ },
52087
+ "data-codingns-translation-action": props.messageId
52088
+ }, (0, react.createElement)("button", {
52089
+ ref: buttonRef,
52090
+ type: "button",
52091
+ title: `${statusText} · ${props.translationT("translation.viewDetails")}`,
52092
+ "aria-label": `${statusText} · ${props.translationT("translation.viewDetails")}`,
52093
+ "aria-expanded": open,
52094
+ "aria-controls": detailsId,
52095
+ onClick: () => setOpen((value) => !value),
52096
+ style: translationButtonStyle
52097
+ }, (0, react.createElement)(TranslationGlyph), (0, react.createElement)("span", {
52098
+ "aria-hidden": true,
52099
+ style: {
52100
+ position: "absolute",
52101
+ top: 1,
52102
+ right: 1,
52103
+ display: "grid",
52104
+ placeItems: "center",
52105
+ width: 10,
52106
+ height: 10,
52107
+ zIndex: 1,
52108
+ boxSizing: "border-box",
52109
+ border: "1.5px solid var(--dsw-alias-bg-base, Canvas)",
52110
+ borderRadius: "50%",
52111
+ color: "#fff",
52112
+ background: failed ? require_theme.dshThemeColor.error : alreadyTargetLanguage ? require_theme.dshThemeColor.accent : require_theme.dshThemeColor.success,
52113
+ fontSize: 6,
52114
+ fontWeight: 700,
52115
+ lineHeight: 1
52116
+ }
52117
+ }, failed ? "!" : "✓")), renderedDetails);
52118
+ }
52119
+ function TranslationGlyph() {
52120
+ return (0, react.createElement)("svg", {
52121
+ viewBox: "0 0 24 24",
52122
+ width: 16,
52123
+ height: 16,
52124
+ fill: "none",
52125
+ stroke: "currentColor",
52126
+ strokeWidth: 1.5,
52127
+ strokeLinecap: "round",
52128
+ strokeLinejoin: "round",
52129
+ "aria-hidden": true
52130
+ }, (0, react.createElement)("path", { d: "M3.5 5.5h10M8.5 3.5v2M12.5 5.5c0 4.4-3.3 7.2-8 9" }), (0, react.createElement)("path", { d: "M5.5 8.5c1.4 2 3.4 3.7 6 4.8M14.5 19.5l3-8 3 8M15.7 17h3.6" }));
52131
+ }
52132
+ const messageActionButtonStyle = {
52133
+ position: "relative",
52134
+ display: "inline-flex",
52135
+ alignItems: "center",
52136
+ justifyContent: "center",
52137
+ width: 28,
52138
+ height: 28,
52139
+ padding: 0,
52140
+ border: 0,
52141
+ borderRadius: "var(--dsw-radius-sm, 6px)",
52142
+ color: require_theme.dshThemeColor.labelTertiary,
52143
+ background: "transparent",
52144
+ cursor: "pointer"
52145
+ };
52146
+ const translationButtonStyle = {
52147
+ ...messageActionButtonStyle,
52148
+ transition: "background-color 100ms ease, color 100ms ease"
52149
+ };
52150
+ function DetailBlock({ label, value }) {
52151
+ return (0, react.createElement)("div", { style: { marginTop: 8 } }, (0, react.createElement)("div", { style: {
52152
+ marginBottom: 3,
52153
+ color: require_theme.dshThemeColor.labelSecondary,
52154
+ fontWeight: 600
52155
+ } }, label), (0, react.createElement)("pre", { style: {
52156
+ margin: 0,
52157
+ whiteSpace: "pre-wrap",
52158
+ overflowWrap: "anywhere",
52159
+ fontFamily: "inherit"
52160
+ } }, value));
52161
+ }
52162
+ /** 按原生 user 节点的结构渲染用户消息,并把翻译按钮放在复制按钮前。 */
52163
+ function UserMessageNodeView(props) {
52164
+ const data = props.node.data;
52165
+ const parts = splitUserContent(data.content);
52166
+ const record = readInputRecord({ source: data.source });
52167
+ if (record === void 0) return null;
52168
+ const translationRecord = inputRecordForAction(record);
52169
+ const labels = Array.isArray(data.referenceLabels) ? data.referenceLabels.filter((label) => typeof label === "string") : [];
52170
+ const skillNames = Array.isArray(data.skillNames) ? data.skillNames.filter((name) => typeof name === "string") : [];
52171
+ const showBubble = parts.text !== "" || parts.rest.length > 0;
52172
+ const compactImages = parts.attachments.filter((attachment) => attachment.type === "image").length > 1;
52173
+ const messageId = `user-${String(data.seq ?? props.node.id ?? "message")}`;
52174
+ const chatT = props.t;
52175
+ return (0, react.createElement)("div", {
52176
+ "data-chat-flow-kind": "user",
52177
+ style: {
52178
+ display: "flex",
52179
+ flexDirection: "column",
52180
+ alignItems: "flex-end",
52181
+ gap: 6
52182
+ }
52183
+ }, (0, react.createElement)("div", { style: {
52184
+ display: "flex",
52185
+ flexDirection: "column",
52186
+ alignItems: "flex-end",
52187
+ gap: 8,
52188
+ minWidth: 0,
52189
+ maxWidth: "min(calc(var(--dsh-chat-content-width, 748px) * .702), 82%)"
52190
+ } }, parts.attachments.length > 0 ? (0, react.createElement)("div", {
52191
+ "data-message-attachments": true,
52192
+ style: {
52193
+ display: "flex",
52194
+ flexWrap: "wrap",
52195
+ justifyContent: "flex-end",
52196
+ gap: 8,
52197
+ maxWidth: "100%"
52198
+ }
52199
+ }, ...parts.attachments.map((attachment, index) => attachment.type === "image" ? (0, react.createElement)("div", { key: `image-${index}` }, props.renderMessageImages({
52200
+ images: [{ attachment: attachment.attachment }],
52201
+ align: "end",
52202
+ compact: compactImages
52203
+ })) : createFileAttachment(attachment.file, index))) : null, showBubble ? (0, react.createElement)("div", { style: {
52204
+ boxSizing: "border-box",
52205
+ maxWidth: "100%",
52206
+ padding: "10px 16px",
52207
+ borderRadius: "var(--dsw-radius-xl, 18px)",
52208
+ color: require_theme.dshThemeColor.labelPrimary,
52209
+ background: "var(--dsw-specific-bubble, var(--dsw-alias-interactive-bg-hover, rgba(127,127,127,.08)))",
52210
+ fontSize: "var(--dsh-content-font-size, 14px)",
52211
+ lineHeight: "calc(22px + var(--dsh-content-font-delta, 0px))",
52212
+ whiteSpace: "pre-wrap",
52213
+ wordBreak: "break-word"
52214
+ } }, (0, _deepseek_ai_dsh_client_ui_primitives.projectUserText)(parts.text, labels, skillNames, "skill", typeof props.openFile === "function" && typeof props.openSkill === "function" ? {
52215
+ openFile: props.openFile,
52216
+ openSkill: props.openSkill
52217
+ } : void 0), ...parts.rest.map((block, index) => (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
52218
+ key: `extra-${index}`,
52219
+ label: chatT("message.extraBlock"),
52220
+ payload: block,
52221
+ truncatedLabel: (total) => chatT("json.truncated", { total })
52222
+ }))) : null), (0, react.createElement)("div", { style: {
52223
+ display: "flex",
52224
+ alignItems: "center",
52225
+ alignSelf: "flex-end",
52226
+ height: "calc(28px + var(--dsh-content-font-delta, 0px))",
52227
+ gap: 8,
52228
+ color: require_theme.dshThemeColor.labelTertiary
52229
+ } }, typeof data.time === "number" ? (0, react.createElement)("span", { style: {
52230
+ paddingRight: 12,
52231
+ color: require_theme.dshThemeColor.labelTertiary,
52232
+ fontSize: "var(--dsh-content-font-size-secondary, 13px)",
52233
+ whiteSpace: "nowrap"
52234
+ } }, formatMessageTime(data.time)) : null, translationRecord === void 0 ? null : (0, react.createElement)(TranslationAction, {
52235
+ messageId,
52236
+ sessionId: props.sessionId,
52237
+ services: props.services,
52238
+ translationT: props.translationT,
52239
+ popupAlign: "end",
52240
+ record: translationRecord
52241
+ }), (0, react.createElement)(CopyAction, {
52242
+ text: parts.text,
52243
+ t: chatT
52244
+ })));
52245
+ }
52246
+ function createFileAttachment(file, index) {
52247
+ const name = typeof file.name === "string" ? file.name : "";
52248
+ const bytes = typeof file.bytes === "number" ? file.bytes : 0;
52249
+ return (0, react.createElement)("span", {
52250
+ key: `file-${index}`,
52251
+ title: name,
52252
+ style: {
52253
+ display: "inline-flex",
52254
+ alignItems: "center",
52255
+ minWidth: 0,
52256
+ maxWidth: "100%",
52257
+ gap: 8,
52258
+ padding: "8px 10px",
52259
+ border: `1px solid ${require_theme.dshThemeColor.border}`,
52260
+ borderRadius: 8,
52261
+ color: require_theme.dshThemeColor.labelPrimary,
52262
+ background: require_theme.dshThemeColor.surfaceSubtle
52263
+ }
52264
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
52265
+ path: name,
52266
+ style: { flex: "none" }
52267
+ }), (0, react.createElement)("span", { style: {
52268
+ display: "flex",
52269
+ flexDirection: "column",
52270
+ minWidth: 0,
52271
+ textAlign: "left"
52272
+ } }, (0, react.createElement)("span", { style: {
52273
+ overflow: "hidden",
52274
+ textOverflow: "ellipsis",
52275
+ whiteSpace: "nowrap"
52276
+ } }, name), (0, react.createElement)("span", { style: {
52277
+ color: require_theme.dshThemeColor.labelSecondary,
52278
+ fontSize: 11
52279
+ } }, [(0, _deepseek_ai_dsh_client_ui_primitives.fileExtension)(name).toUpperCase().slice(0, 8), (0, _deepseek_ai_dsh_client_ui_primitives.fileSizeText)(bytes)].filter(Boolean).join(" "))));
52280
+ }
52281
+ function CopyAction({ text, t: chatT }) {
52282
+ const [copied, setCopied] = (0, react.useState)(false);
52283
+ const timer = (0, react.useRef)(void 0);
52284
+ (0, react.useEffect)(() => () => {
52285
+ if (timer.current !== void 0) clearTimeout(timer.current);
52286
+ }, []);
52287
+ return (0, react.createElement)("button", {
52288
+ type: "button",
52289
+ title: copied ? chatT("copied") : chatT("copy"),
52290
+ "aria-label": copied ? chatT("copied") : chatT("copy"),
52291
+ onClick: () => {
52292
+ (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(text).then((success) => {
52293
+ if (!success) return;
52294
+ setCopied(true);
52295
+ if (timer.current !== void 0) clearTimeout(timer.current);
52296
+ timer.current = setTimeout(() => {
52297
+ timer.current = void 0;
52298
+ setCopied(false);
52299
+ }, 1e3);
52300
+ });
52301
+ },
52302
+ style: messageActionButtonStyle
52303
+ }, (0, react.createElement)(copied ? _deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular : _deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular));
52304
+ }
52305
+ function splitUserContent(content) {
52306
+ const text = [];
52307
+ const attachments = [];
52308
+ const rest = [];
52309
+ if (typeof content === "string") return {
52310
+ text: content,
52311
+ attachments,
52312
+ rest
52313
+ };
52314
+ if (!Array.isArray(content)) return {
52315
+ text: "",
52316
+ attachments,
52317
+ rest
52318
+ };
52319
+ for (const value of content) {
52320
+ const block = asRecord(value);
52321
+ if (block?.type === "text" && typeof block.text === "string") text.push(block.text);
52322
+ else if (block?.type === "image" && block.attachment !== void 0) attachments.push({
52323
+ type: "image",
52324
+ attachment: block.attachment
52325
+ });
52326
+ else if (block?.type === "file" && asRecord(block.attachment) !== void 0) attachments.push({
52327
+ type: "file",
52328
+ file: asRecord(block.attachment)
52329
+ });
52330
+ else rest.push(value);
52331
+ }
52332
+ return {
52333
+ text: text.join(""),
52334
+ attachments,
52335
+ rest
52336
+ };
52337
+ }
52338
+ function formatMessageTime(time) {
52339
+ const date = new Date(time);
52340
+ const now = /* @__PURE__ */ new Date();
52341
+ const options = date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate() ? {
52342
+ hour: "2-digit",
52343
+ minute: "2-digit"
52344
+ } : {
52345
+ ...date.getFullYear() === now.getFullYear() ? {} : { year: "numeric" },
52346
+ month: "2-digit",
52347
+ day: "2-digit",
52348
+ hour: "2-digit",
52349
+ minute: "2-digit"
52350
+ };
52351
+ return new Intl.DateTimeFormat(void 0, options).format(date);
52352
+ }
52353
+ /** DSH assistant-step renderer: keep each translated text/reasoning block's source action adjacent to that block. */
52354
+ function AssistantTranslationNodeView(props) {
52355
+ const data = props.node.data;
52356
+ const blocks = Array.isArray(data.blocks) ? data.blocks : [];
52357
+ const streaming = data.status === "running";
52358
+ const chatT = props.t;
52359
+ const markdownLabels = (0, react.useMemo)(() => createMarkdownLabels(chatT), [chatT]);
52360
+ const pathImages = (0, react.useMemo)(() => ({ resolve: resolveMarkdownImagePath }), []);
52361
+ const eventSnapshot = readEventSource(props.services, props.sessionId)?.getSnapshot();
52362
+ const hasTranslation = blocks.some((block) => {
52363
+ if (block.kind !== "reasoning" && block.kind !== "text") return false;
52364
+ const outputKind = block.kind === "reasoning" ? "reasoning" : "assistant";
52365
+ const embedded = readRecord(block);
52366
+ if (embedded !== void 0 && (embedded.outputKind === void 0 || embedded.outputKind === outputKind)) return true;
52367
+ return eventSnapshot !== void 0 && findTranslationRecordForText(eventSnapshot, block.text, outputKind, data.turn, data.step) !== void 0;
52368
+ });
52369
+ const turn = props.node.location?.kind === "turn" || props.node.location?.kind === "step" ? props.node.location.turn : void 0;
52370
+ const tail = typeof props.useTurnData === "function" ? props.useTurnData("turn-tail") : void 0;
52371
+ const finalNode = data.finalNode;
52372
+ const fileOwner = turn?.status === "closed" && finalNode !== void 0 && tail?.closing?.finalNode?.seq === finalNode.seq ? {
52373
+ turn,
52374
+ seq: finalNode.seq,
52375
+ openFile: (path) => {
52376
+ props.openFile(path);
52377
+ }
52378
+ } : void 0;
52379
+ const mentions = fileOwner === void 0 || typeof props.fileMentions !== "function" ? void 0 : props.fileMentions(fileOwner);
52380
+ const turnProcess = props.turnProcess;
52381
+ const reasoningHidden = turnProcess !== void 0 && turnProcess.foldable === true && turnProcess.spec?.answerStep === data.step && turnProcess.spec?.inlineReasoning === true && turnProcess.open !== true;
52382
+ const rendered = [];
52383
+ const last = blocks.length - 1;
52384
+ const messageId = typeof finalNode?.messageId === "string" ? finalNode.messageId : `turn-${data.turn}-step-${data.step}`;
52385
+ if (!hasTranslation || !(streaming || data.status === "interrupted" || blocks.some((block) => block.kind !== "tool-call"))) return null;
52386
+ for (let index = 0; index < blocks.length; index += 1) {
52387
+ const block = blocks[index];
52388
+ if (block === void 0) continue;
52389
+ if (props.groupPart === "reasoning" && block.kind !== "reasoning") continue;
52390
+ if (props.groupPart === "response" && block.kind === "reasoning") continue;
52391
+ const running = streaming && index === last;
52392
+ if (block.kind === "text") {
52393
+ const translationRecord = readRecord(block);
52394
+ rendered.push((0, react.createElement)("div", {
52395
+ key: `text-${index}`,
52396
+ "data-codingns-translation-inline": true,
52397
+ style: { minWidth: 0 }
52398
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
52399
+ text: block.text,
52400
+ streaming,
52401
+ labels: markdownLabels,
52402
+ fileMentions: mentions,
52403
+ pathImages
52404
+ }), (0, react.createElement)(TranslationAction, {
52405
+ messageId: `${messageId}-text-${index}`,
52406
+ sessionId: props.sessionId,
52407
+ services: props.services,
52408
+ translationT: props.translationT,
52409
+ lookupText: block.text,
52410
+ outputKind: "assistant",
52411
+ turn: data.turn,
52412
+ step: data.step,
52413
+ inline: true,
52414
+ ...translationRecord === void 0 ? {} : { record: translationRecord }
52415
+ })));
52416
+ continue;
52417
+ }
52418
+ if (block.kind === "reasoning") {
52419
+ rendered.push((0, react.createElement)(AssistantReasoningBlock, {
52420
+ key: `reasoning-${index}`,
52421
+ messageId: `${messageId}-reasoning-${index}`,
52422
+ sessionId: props.sessionId,
52423
+ services: props.services,
52424
+ translationT: props.translationT,
52425
+ chatT,
52426
+ text: block.text,
52427
+ turn: data.turn,
52428
+ step: data.step,
52429
+ running,
52430
+ hidden: reasoningHidden,
52431
+ reveal: () => turnProcess?.setOpen?.(true),
52432
+ useGroupAction: props.useGroupAction,
52433
+ renderFactorySlot: props.renderFactorySlot,
52434
+ markdownLabels,
52435
+ pathImages,
52436
+ mentions
52437
+ }));
52438
+ continue;
52439
+ }
52440
+ if (block.kind === "image") {
52441
+ const imageGroup = [block];
52442
+ while (index + 1 < blocks.length && blocks[index + 1]?.kind === "image") {
52443
+ const next = blocks[index + 1];
52444
+ if (next?.kind !== "image") break;
52445
+ imageGroup.push(next);
52446
+ index += 1;
52447
+ }
52448
+ rendered.push((0, react.createElement)("div", {
52449
+ key: `images-${index}`,
52450
+ style: { alignSelf: "flex-start" }
52451
+ }, props.renderMessageImages({
52452
+ images: imageGroup.map((image) => ({ attachment: image.attachment })),
52453
+ align: "start"
52454
+ })));
52455
+ continue;
52456
+ }
52457
+ if (block.kind === "other") rendered.push((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
52458
+ key: `other-${index}`,
52459
+ label: chatT("message.unknownBlock"),
52460
+ payload: block.block,
52461
+ truncatedLabel: (total) => chatT("json.truncated", { total })
52462
+ }));
52463
+ }
52464
+ return (0, react.createElement)("div", {
52465
+ "data-streaming": streaming || void 0,
52466
+ style: {
52467
+ display: "flex",
52468
+ flexDirection: "column",
52469
+ gap: 16,
52470
+ minWidth: 0,
52471
+ color: require_theme.dshThemeColor.labelPrimary,
52472
+ fontSize: "var(--dsh-content-font-size, 14px)",
52473
+ lineHeight: "calc(24px + var(--dsh-content-font-delta, 0px))"
52474
+ }
52475
+ }, ...rendered, data.status === "interrupted" ? (0, react.createElement)("span", { style: {
52476
+ alignSelf: "flex-start",
52477
+ padding: "0 6px",
52478
+ borderRadius: "var(--dsw-radius-sm, 4px)",
52479
+ color: require_theme.dshThemeColor.labelTertiary,
52480
+ background: require_theme.dshThemeColor.surfaceSubtle,
52481
+ fontSize: 11,
52482
+ lineHeight: "18px"
52483
+ } }, chatT("message.stopped")) : null);
52484
+ }
52485
+ function AssistantReasoningBlock(props) {
52486
+ const [expanded, setExpanded] = (0, react.useState)(false);
52487
+ const groupRef = props.useGroupAction?.(props.hidden, props.reveal);
52488
+ const summary = props.text.split("\n").map((line) => line.replace(/[`*_#>]/gu, "").trim()).find(Boolean) ?? "";
52489
+ const markdown = props.renderFactorySlot === void 0 ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
52490
+ text: props.text,
52491
+ streaming: props.running,
52492
+ labels: props.markdownLabels,
52493
+ fileMentions: props.mentions,
52494
+ pathImages: props.pathImages,
52495
+ variant: "compact"
52496
+ }) : props.renderFactorySlot("conversation.chat.reasoning.content", {
52497
+ text: props.text,
52498
+ running: props.running
52499
+ });
52500
+ return (0, react.createElement)("div", {
52501
+ ref: groupRef,
52502
+ hidden: props.hidden,
52503
+ "data-turn-process-inline": props.hidden || void 0
52504
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
52505
+ icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconThinkOutlineRegular, { size: 14 }),
52506
+ title: props.chatT("message.think"),
52507
+ open: expanded,
52508
+ expandable: true,
52509
+ expandOnRowClick: true,
52510
+ running: props.running,
52511
+ onToggle: () => setExpanded((value) => !value),
52512
+ collapsedContent: (0, react.createElement)("span", { style: {
52513
+ minWidth: 0,
52514
+ overflow: "hidden",
52515
+ color: require_theme.dshThemeColor.labelSecondary,
52516
+ fontSize: "var(--dsh-content-font-size-secondary, 13px)",
52517
+ textOverflow: "ellipsis",
52518
+ whiteSpace: "nowrap"
52519
+ } }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.TextShimmer, {
52520
+ active: props.running,
52521
+ children: summary
52522
+ }))
52523
+ }, expanded ? (0, react.createElement)("div", {
52524
+ "data-codingns-translation-inline": true,
52525
+ style: { paddingTop: 8 }
52526
+ }, markdown, (0, react.createElement)(TranslationAction, {
52527
+ messageId: props.messageId,
52528
+ sessionId: props.sessionId,
52529
+ services: props.services,
52530
+ translationT: props.translationT,
52531
+ lookupText: props.text,
52532
+ outputKind: "reasoning",
52533
+ ...props.turn === void 0 ? {} : { turn: props.turn },
52534
+ ...props.step === void 0 ? {} : { step: props.step },
52535
+ inline: true
52536
+ })) : null));
52537
+ }
52538
+ function createMarkdownLabels(chatT) {
52539
+ return {
52540
+ code: {
52541
+ copyLabel: chatT("copy"),
52542
+ copiedLabel: chatT("copied"),
52543
+ toolbarLabels: {
52544
+ codeLabel: chatT("codeBlock.title"),
52545
+ wrapLabel: chatT("codeBlock.wrap"),
52546
+ unwrapLabel: chatT("codeBlock.unwrap")
52547
+ }
52548
+ },
52549
+ footnotes: chatT("markdown.footnotes")
52550
+ };
52551
+ }
52552
+ function resolveMarkdownImagePath(value) {
52553
+ if (typeof document === "undefined" || !value.startsWith("/") || /^[/\\]{2}/u.test(value) || /[\u0000-\u001f\u007f]/u.test(value)) return void 0;
52554
+ const base = document.baseURI;
52555
+ if (!/^https?:/u.test(base) && !base.startsWith("dsh-app://app/")) return void 0;
52556
+ try {
52557
+ return new URL(`api/file?path=${encodeURIComponent(value)}`, base).href;
52558
+ } catch {
52559
+ return;
52560
+ }
52561
+ }
52562
+ /**
52563
+ * 注册两个有实际翻译记录的消息渲染器;DSH 的用户气泡内容仍由统一主题令牌控制。
52564
+ */
52565
+ function registerSessionTranslationChatUi(services) {
52566
+ const slots = services.slots;
52567
+ if (slots?.inject === void 0 || slots.register === void 0) return () => void 0;
52568
+ const removeStyles = installSessionTranslationChatStyles();
52569
+ const translationT = services.locale.bind("codingns");
52570
+ const removeUserRenderer = slots.inject("conversation.chat.node", () => slots.register({
52571
+ name: "conversation.chat.node",
52572
+ key: "user",
52573
+ priority: -100,
52574
+ locale: "chat",
52575
+ inject: (sessionId) => ({
52576
+ services,
52577
+ sessionId,
52578
+ translationT
52579
+ })
52580
+ }, UserMessageNodeView));
52581
+ const removeAssistantRenderer = slots.inject("conversation.chat.node", () => slots.register({
52582
+ name: "conversation.chat.node",
52583
+ key: "assistant-step",
52584
+ priority: -100,
52585
+ locale: "chat",
52586
+ inject: (sessionId) => ({
52587
+ services,
52588
+ sessionId,
52589
+ translationT
52590
+ })
52591
+ }, AssistantTranslationNodeView));
52592
+ return () => {
52593
+ removeAssistantRenderer();
52594
+ removeUserRenderer();
52595
+ removeStyles();
52596
+ };
52597
+ }
52598
+ function installSessionTranslationChatStyles() {
52599
+ if (typeof document === "undefined") return () => void 0;
52600
+ const styleId = "codingns-session-translation-chat";
52601
+ if (document.head.querySelector(`style[data-plugin-css="${styleId}"]`) !== null) return () => void 0;
52602
+ const style = document.createElement("style");
52603
+ style.dataset.plugin = "codingns4dsh";
52604
+ style.dataset.pluginCss = styleId;
52605
+ style.textContent = `
52606
+ [data-codingns-translation-inline] > div:not([data-codingns-translation-action]){display:contents}
52607
+ [data-codingns-translation-inline] > div:not([data-codingns-translation-action]) > p:last-child{display:inline;margin:0}
52608
+ `;
52609
+ document.head.appendChild(style);
52610
+ return () => style.remove();
52611
+ }
52612
+ function readEventSource(services, sessionId) {
52613
+ const sessions = services.sessions;
52614
+ try {
52615
+ return sessions?.binding?.(sessionId)?.eventSource;
52616
+ } catch {
52617
+ return;
52618
+ }
52619
+ }
52620
+ function findTranslationRecordForText(snapshot, text, outputKind, turn, step) {
52621
+ const entries = snapshot.entries ?? [];
52622
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
52623
+ const event = readEntryEvent(entries[index]);
52624
+ if (event === void 0 || !event.type.startsWith("assistant/")) continue;
52625
+ const eventData = asRecord(event.data);
52626
+ if (turn !== void 0 && typeof eventData?.turn === "number" && eventData.turn !== turn) continue;
52627
+ if (step !== void 0 && typeof eventData?.step === "number" && eventData.step !== step) continue;
52628
+ const candidates = [];
52629
+ collectRecordCandidates(event.data, candidates, /* @__PURE__ */ new Set());
52630
+ for (const candidate of candidates) {
52631
+ const record = readRecord(candidate);
52632
+ if (record === void 0 || record.translated !== text) continue;
52633
+ if (outputKind !== void 0 && record.outputKind !== void 0 && record.outputKind !== outputKind) continue;
52634
+ return record;
52635
+ }
52636
+ }
52637
+ }
52638
+ function collectRecordCandidates(value, candidates, seen, depth = 0) {
52639
+ if (Array.isArray(value)) {
52640
+ for (const item of value) collectRecordCandidates(item, candidates, seen, depth + 1);
52641
+ return;
52642
+ }
52643
+ const record = asRecord(value);
52644
+ if (record === void 0 || seen.has(record) || depth > 7) return;
52645
+ seen.add(record);
52646
+ if (readRecord(record) !== void 0 || asRecord(record.codingnsTranslation) !== void 0) candidates.push(record);
52647
+ for (const key of [
52648
+ "codingnsTranslation",
52649
+ "source",
52650
+ "message",
52651
+ "content",
52652
+ "stream",
52653
+ "chunk",
52654
+ "block",
52655
+ "data"
52656
+ ]) if (record[key] !== void 0) collectRecordCandidates(record[key], candidates, seen, depth + 1);
52657
+ }
52658
+ function readEntryEvent(value) {
52659
+ const record = asRecord(value);
52660
+ return asRecord(record?.event) ?? (typeof record?.type === "string" ? record : void 0);
52661
+ }
52662
+ function readRecord(value) {
52663
+ const record = asRecord(value);
52664
+ const candidate = asRecord(record?.codingnsTranslation) ?? record;
52665
+ if (candidate?.original === void 0 || candidate.translated === void 0) return void 0;
52666
+ if (typeof candidate.original !== "string" || typeof candidate.translated !== "string") return void 0;
52667
+ const targetLanguage = readLanguage(candidate.targetLanguage);
52668
+ if (targetLanguage === void 0) return void 0;
52669
+ const model = readModel(candidate.model);
52670
+ const outputKind = candidate.outputKind === "assistant" || candidate.outputKind === "reasoning" ? candidate.outputKind : void 0;
52671
+ return {
52672
+ original: candidate.original,
52673
+ translated: candidate.translated,
52674
+ ...candidate.sourceLanguage === "zh" || candidate.sourceLanguage === "en" || candidate.sourceLanguage === "fr" || candidate.sourceLanguage === "de" || candidate.sourceLanguage === "ja" ? { sourceLanguage: candidate.sourceLanguage } : {},
52675
+ targetLanguage,
52676
+ bilingual: candidate.bilingual === true,
52677
+ ...outputKind === void 0 ? {} : { outputKind },
52678
+ ...candidate.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
52679
+ ...model === void 0 ? {} : { model },
52680
+ ...candidate.failed === true ? { failed: true } : {}
52681
+ };
52682
+ }
52683
+ function readModel(value) {
52684
+ const record = asRecord(value);
52685
+ if (typeof record?.provider !== "string" || typeof record.model !== "string" || record.provider.trim() === "" || record.model.trim() === "") return void 0;
52686
+ return {
52687
+ provider: record.provider,
52688
+ model: record.model
52689
+ };
52690
+ }
52691
+ function readInputRecord(value) {
52692
+ const candidate = asRecord(asRecord(asRecord(value)?.source)?.codingnsTranslationInput);
52693
+ if (candidate?.original === void 0 || candidate.translated === void 0) return void 0;
52694
+ if (typeof candidate.original !== "string" || typeof candidate.translated !== "string") return void 0;
52695
+ const targetLanguage = candidate.targetLanguage;
52696
+ if (targetLanguage !== "en" && targetLanguage !== "fr" && targetLanguage !== "de" && targetLanguage !== "ja") return void 0;
52697
+ const model = readModel(candidate.model);
52698
+ return {
52699
+ original: candidate.original,
52700
+ translated: candidate.translated,
52701
+ ...candidate.sourceLanguage === "zh" || candidate.sourceLanguage === "en" || candidate.sourceLanguage === "fr" || candidate.sourceLanguage === "de" || candidate.sourceLanguage === "ja" ? { sourceLanguage: candidate.sourceLanguage } : {},
52702
+ targetLanguage,
52703
+ ...candidate.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
52704
+ ...model === void 0 ? {} : { model },
52705
+ ...candidate.failed === true ? { failed: true } : {}
52706
+ };
52707
+ }
52708
+ function inputRecordForAction(record) {
52709
+ return {
52710
+ original: record.original,
52711
+ translated: record.translated,
52712
+ ...record.sourceLanguage === void 0 ? {} : { sourceLanguage: record.sourceLanguage },
52713
+ targetLanguage: record.targetLanguage,
52714
+ bilingual: false,
52715
+ ...record.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
52716
+ ...record.model === void 0 ? {} : { model: record.model },
52717
+ ...record.failed === true ? { failed: true } : {}
52718
+ };
52719
+ }
52720
+ function readLanguage(value) {
52721
+ return value === "zh" || value === "en" || value === "fr" || value === "de" || value === "ja" ? value : void 0;
52722
+ }
52723
+ function formatModel(model, t) {
52724
+ return model === void 0 ? t("translation.modelUnknown") : `${model.provider} / ${model.model}`;
52725
+ }
52726
+ function safeDomId(value) {
52727
+ return encodeURIComponent(value).replace(/%/gu, "-");
52728
+ }
52729
+ function asRecord(value) {
52730
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
52731
+ }
52732
+ //#endregion
52733
+ //#region src/client/features/session-translation.ts
52734
+ const languageLabelKeys = {
52735
+ zh: "translation.language.zh",
52736
+ en: "translation.language.en",
52737
+ fr: "translation.language.fr",
52738
+ de: "translation.language.de",
52739
+ ja: "translation.language.ja"
52740
+ };
52741
+ const sessionTranslationFeature = {
52742
+ descriptor: {
52743
+ name: "sessionTranslation",
52744
+ version: "0.1.0",
52745
+ enabledByDefault: false,
52746
+ dependencies: ["cliAdapters"],
52747
+ runtime: "client",
52748
+ ui: {
52749
+ label: "Session translation",
52750
+ description: "Translate selected external Agent requests and replies without changing tools, commands, paths, or original history.",
52751
+ labelKey: "feature.sessionTranslation.label",
52752
+ descriptionKey: "feature.sessionTranslation.description",
52753
+ order: 32,
52754
+ defaultOpen: true
52755
+ }
52756
+ },
52757
+ start: (context) => {
52758
+ return registerSessionTranslationChatUi(context.services);
52759
+ },
52760
+ settingsPanel: SessionTranslationPanel
52761
+ };
52762
+ function SessionTranslationPanel({ services, enabled, snapshot, notify }) {
52763
+ const t = require_transport.useCodingNsTranslator(services.locale);
52764
+ const value = snapshot.value?.sessionTranslation ?? require_native_workspace_store.DEFAULT_CODINGNS_SETTINGS.sessionTranslation ?? require_session_translation.DEFAULT_SESSION_TRANSLATION_SETTINGS;
52765
+ const disabled = !enabled || snapshot.status === "loading" || !snapshot.writable;
52766
+ const [catalog, setCatalog] = (0, react.useState)(null);
52767
+ (0, react.useEffect)(() => {
52768
+ let active = true;
52769
+ require_model_catalog_cache.callCliRpc(services.rpc, "translation/models", {}, AbortSignal.timeout(1e4)).then((value) => {
52770
+ if (active) setCatalog(value);
52771
+ }).catch(() => void 0);
52772
+ return () => {
52773
+ active = false;
52774
+ };
52775
+ }, [services.rpc]);
52776
+ const save = (patch) => {
52777
+ const next = Object.fromEntries(Object.entries({
52778
+ ...value,
52779
+ ...patch
52780
+ }).filter(([, item]) => item !== void 0));
52781
+ services.settings.set(require_native_workspace_store.CODINGNS_SESSION_TRANSLATION_FIELD, next).then((written) => {
52782
+ if (!written) throw new Error(t("translation.saveRejected"));
52783
+ notify({
52784
+ kind: "success",
52785
+ message: t("translation.saved")
52786
+ });
52787
+ }).catch((error) => notify({
52788
+ kind: "error",
52789
+ message: error instanceof Error ? error.message : String(error)
52790
+ }));
52791
+ };
52792
+ return (0, react.createElement)("div", {
52793
+ "aria-disabled": disabled,
52794
+ style: {
52795
+ ...require_theme.dshFormRootStyle,
52796
+ display: "flex",
52797
+ flexDirection: "column",
52798
+ gap: 0,
52799
+ opacity: disabled ? .55 : 1,
52800
+ pointerEvents: disabled ? "none" : "auto"
52801
+ }
52802
+ }, (0, react.createElement)("div", { style: {
52803
+ ...require_theme.dshSettingsSectionHeaderStyle,
52804
+ marginTop: 0
52805
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("translation.inputTitle"))), (0, react.createElement)(Field, { label: t("translation.inputLanguage") }, (0, react.createElement)("select", {
52806
+ value: value.inputLanguage,
52807
+ disabled,
52808
+ style: require_theme.dshSettingsFieldStyle,
52809
+ onChange: (event) => save({ inputLanguage: readInputLanguage(event.currentTarget.value) })
52810
+ }, ...[
52811
+ "en",
52812
+ "fr",
52813
+ "de",
52814
+ "ja"
52815
+ ].map((language) => (0, react.createElement)("option", {
52816
+ key: language,
52817
+ value: language
52818
+ }, t(languageLabelKeys[language]))))), (0, react.createElement)("div", { style: {
52819
+ ...require_theme.dshSettingsSectionHeaderStyle,
52820
+ marginTop: 12
52821
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("translation.outputTitle"))), (0, react.createElement)(Field, { label: t("translation.outputLanguage") }, (0, react.createElement)("select", {
52822
+ value: value.outputLanguage,
52823
+ disabled,
52824
+ style: require_theme.dshSettingsFieldStyle,
52825
+ onChange: (event) => save({ outputLanguage: readOutputLanguage(event.currentTarget.value) })
52826
+ }, ...[
52827
+ "zh",
52828
+ "en",
52829
+ "fr",
52830
+ "de",
52831
+ "ja"
52832
+ ].map((language) => (0, react.createElement)("option", {
52833
+ key: language,
52834
+ value: language
52835
+ }, t(languageLabelKeys[language]))))), (0, react.createElement)("div", { style: {
52836
+ ...require_theme.dshSettingsSectionHeaderStyle,
52837
+ marginTop: 12
52838
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("translation.modelTitle"))), (0, react.createElement)(ModelField, {
52839
+ value,
52840
+ catalog,
52841
+ disabled,
52842
+ t,
52843
+ onChange: (model) => save({ translationModel: model })
52844
+ }));
52845
+ }
52846
+ function Field({ label, children }) {
52847
+ return (0, react.createElement)("label", { style: {
52848
+ ...require_theme.dshSettingsListRowStyle,
52849
+ alignItems: "flex-start",
52850
+ flexDirection: "column",
52851
+ gap: 6
52852
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, label), children ?? null);
52853
+ }
52854
+ function ModelField({ value, catalog, disabled, t, onChange }) {
52855
+ const selectedKey = value.translationModel === void 0 ? "" : JSON.stringify([value.translationModel.provider, value.translationModel.model]);
52856
+ const models = catalog?.models ?? [];
52857
+ const hasSelected = selectedKey !== "" && models.some((model) => JSON.stringify([model.provider, model.model]) === selectedKey);
52858
+ return (0, react.createElement)("div", { style: {
52859
+ width: "100%",
52860
+ display: "grid",
52861
+ gap: 6
52862
+ } }, (0, react.createElement)("select", {
52863
+ value: selectedKey,
52864
+ disabled,
52865
+ style: require_theme.dshSettingsFieldStyle,
52866
+ onChange: (event) => onChange(readTranslationModel(event.currentTarget.value))
52867
+ }, (0, react.createElement)("option", { value: "" }, t("translation.modelFollowDefault")), !hasSelected && selectedKey !== "" && (0, react.createElement)("option", { value: selectedKey }, t("translation.modelUnavailable")), ...models.map((model) => (0, react.createElement)("option", {
52868
+ key: JSON.stringify([model.provider, model.model]),
52869
+ value: JSON.stringify([model.provider, model.model])
52870
+ }, `${isOfficialProvider(model.provider) ? t("translation.modelOfficial") : t("translation.modelThirdParty")} · ${model.label}`))), catalog === null ? (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, t("translation.modelLoading")) : models.length === 0 ? (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, t("translation.modelEmpty")) : (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, t("translation.modelHelp")));
52871
+ }
52872
+ function readTranslationModel(value) {
52873
+ if (value === "") return void 0;
52874
+ try {
52875
+ const parsed = JSON.parse(value);
52876
+ if (!Array.isArray(parsed) || typeof parsed[0] !== "string" || typeof parsed[1] !== "string" || parsed[0].trim() === "" || parsed[1].trim() === "") return void 0;
52877
+ return {
52878
+ provider: parsed[0],
52879
+ model: parsed[1]
52880
+ };
52881
+ } catch {
52882
+ return;
52883
+ }
52884
+ }
52885
+ function isOfficialProvider(provider) {
52886
+ return /^(?:deepseek(?:-official)?|official-deepseek)$/iu.test(provider.trim());
52887
+ }
52888
+ function readInputLanguage(value) {
52889
+ return value === "fr" || value === "de" || value === "ja" ? value : "en";
52890
+ }
52891
+ function readOutputLanguage(value) {
52892
+ return value === "en" || value === "fr" || value === "de" || value === "ja" ? value : "zh";
52893
+ }
52894
+ //#endregion
51692
52895
  //#region src/features/host-router.ts
51693
52896
  /** 统一管理当前 Host/PeerHost 的完整作用域和 generation。 */
51694
52897
  var HostRouter = class {
@@ -51918,7 +53121,8 @@ ${scope} [data-dockkit-strip-tabs] {
51918
53121
  fileManagementFeature,
51919
53122
  peerHostFeature,
51920
53123
  globalVoiceAssistantFeature,
51921
- subagentCollapsedLineageFeature
53124
+ subagentCollapsedLineageFeature,
53125
+ sessionTranslationFeature
51922
53126
  ];
51923
53127
  /**
51924
53128
  * 汇总需要在设置页显示的模块,按 ui.order 升序。
@@ -59056,6 +60260,118 @@ ${scope} [data-dockkit-strip-tabs] {
59056
60260
  };
59057
60261
  }
59058
60262
  //#endregion
60263
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.1-alpha.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
60264
+ /**
60265
+ * The `dsh-resource://file/…` address grammar: how a file is named across the
60266
+ * Sidebar and the resource model, built and parsed without touching a
60267
+ * filesystem.
60268
+ * @module
60269
+ */
60270
+ /** The scheme and type every file address opens with. */
60271
+ const FILE_ADDRESS_PREFIX = "dsh-resource://file/";
60272
+ /** Component-encode one id or path segment, keeping `:` literal for drive letters. */
60273
+ function encodeSegment(segment) {
60274
+ return encodeURIComponent(segment).replace(/%3A/gi, ":");
60275
+ }
60276
+ /** Encode a `/`-separated path segment by segment. */
60277
+ function encodePath(path) {
60278
+ return path.split("/").map(encodeSegment).join("/");
60279
+ }
60280
+ /** Whether a decoded first path segment is a Windows drive (`C:`). */
60281
+ function isDriveSegment(segment) {
60282
+ return segment !== void 0 && /^[A-Za-z]:$/.test(segment);
60283
+ }
60284
+ /**
60285
+ * Build the address of a file read through one Session.
60286
+ * @param sessionId - the Session whose Host workspace resolves the path.
60287
+ * @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
60288
+ * @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
60289
+ */
60290
+ function sessionFileAddress(sessionId, path) {
60291
+ const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
60292
+ return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
60293
+ }
60294
+ /**
60295
+ * Read a file address back into its parts without resolving `.` or `..`.
60296
+ * Query and fragment suffixes are ignored; encoded path segments are decoded.
60297
+ * @param address - a candidate address.
60298
+ * @returns the parts, or `undefined` when the string is not a `dsh-resource://file/` URI in a known scope with a path, or a segment is not validly encoded.
60299
+ */
60300
+ function parseFileAddress(address) {
60301
+ try {
60302
+ if (!address.startsWith(FILE_ADDRESS_PREFIX)) return void 0;
60303
+ const end = address.search(/[?#]/);
60304
+ const [scope, ...rest] = address.slice(20, end === -1 ? void 0 : end).split("/");
60305
+ if (scope === "session") {
60306
+ const [id, ...segments] = rest;
60307
+ if (id === void 0 || id === "" || segments.length === 0) return void 0;
60308
+ return {
60309
+ scope,
60310
+ sessionId: decodeURIComponent(id),
60311
+ path: segments.map(decodeURIComponent).join("/")
60312
+ };
60313
+ }
60314
+ if (scope === "absolute") {
60315
+ const unc = rest[0] === "" && rest.length > 1;
60316
+ const segments = (unc ? rest.slice(1) : rest).map(decodeURIComponent);
60317
+ if (segments.length === 0 || segments[0] === "") return void 0;
60318
+ if (unc) return {
60319
+ scope,
60320
+ path: `//${segments.join("/")}`
60321
+ };
60322
+ return {
60323
+ scope,
60324
+ path: isDriveSegment(segments[0]) ? segments.join("/") : `/${segments.join("/")}`
60325
+ };
60326
+ }
60327
+ return;
60328
+ } catch {
60329
+ return;
60330
+ }
60331
+ }
60332
+ //#endregion
60333
+ //#region src/client/session-file-links.ts
60334
+ /**
60335
+ * 在原生资源入口规范本地及远端链接,保留资源里的会话身份和导航参数。
60336
+ * 右栏文件树、消息与预览内链接共用这个入口;不扫描消息正文或当前选择。
60337
+ */
60338
+ function installSessionFileLinkRouting(uiContext, workspacePathForSession) {
60339
+ const sidebar = uiContext.get("sidebarRight");
60340
+ if (typeof sidebar?.openResource !== "function") return void 0;
60341
+ const originalOpen = sidebar.openResource;
60342
+ const originalOpenIn = sidebar.openResourceIn;
60343
+ const resolve = (address, options) => {
60344
+ const file = parseFileAddress(address);
60345
+ if (file?.scope !== "session") return [address, options];
60346
+ const location = normalizePeerHostFileLocation(file.path, workspacePathForSession(file.sessionId));
60347
+ if (location.path === file.path) return [address, options];
60348
+ const suffix = address.search(/[?#]/u);
60349
+ return [sessionFileAddress(file.sessionId, location.path) + (suffix < 0 ? "" : address.slice(suffix)), location.line === void 0 ? options : {
60350
+ ...options,
60351
+ params: {
60352
+ line: location.line,
60353
+ ...options?.params
60354
+ }
60355
+ }];
60356
+ };
60357
+ const open = (address, options) => originalOpen.call(sidebar, ...resolve(address, options));
60358
+ const openIn = originalOpenIn === void 0 ? void 0 : (sessionId, address, options) => originalOpenIn.call(sidebar, sessionId, ...resolve(address, options));
60359
+ sidebar.openResource = open;
60360
+ if (openIn !== void 0) sidebar.openResourceIn = openIn;
60361
+ return () => {
60362
+ if (sidebar.openResource === open) sidebar.openResource = originalOpen;
60363
+ if (openIn !== void 0 && sidebar.openResourceIn === openIn) sidebar.openResourceIn = originalOpenIn;
60364
+ };
60365
+ }
60366
+ /** 独立于 PeerHost 开关,按资源所属会话的最新目录识别路径平台。 */
60367
+ function installNativeSessionFileLinkRouting(uiContext) {
60368
+ const sessions = require_native_workspace_store.readNativeService(uiContext, "sessions", "list");
60369
+ return installSessionFileLinkRouting(uiContext, (sessionId) => {
60370
+ const workspace = require_native_workspace_store.readNativeWorkspaceSnapshot(uiContext)?.items.find((item) => item.sessionIds.includes(sessionId));
60371
+ return workspace?.workspacePath ?? sessions?.getSnapshot().byId?.[sessionId]?.cwd ?? workspace?.path;
60372
+ });
60373
+ }
60374
+ //#endregion
59059
60375
  //#region node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/util.js
59060
60376
  function getEnumValues(entries) {
59061
60377
  const numericValues = Object.values(entries).filter((v) => typeof v === "number");
@@ -64677,6 +65993,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
64677
65993
  require_model_catalog_cache.debugInfo("codingns4dsh: client apply entered", { dshVersion });
64678
65994
  ensureCryptoRandomUUID();
64679
65995
  ctx.effect(() => require_transport.registerCodingNsLocale(ctx), "codingns4dsh: client dictionaries");
65996
+ ctx.inject([
65997
+ "sidebarRight",
65998
+ "sessions",
65999
+ "workspaces"
66000
+ ], (scope) => {
66001
+ scope.effect(() => installNativeSessionFileLinkRouting(scope) ?? (() => void 0), "codingns4dsh: session file links");
66002
+ });
64680
66003
  ctx.inject([
64681
66004
  "slots",
64682
66005
  "connection",
@@ -64933,5 +66256,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
64933
66256
  });
64934
66257
 
64935
66258
  })();
64936
- // codingns-client-revision: 57b5a1913b81a5622939394cfb36c6a9b62c943b5dabb6f7b8e5b15dfaddb3da
66259
+ // codingns-client-revision: 357fbcae0ed92ae51010b9952fb1be86dedea3232628e2c830758032a3e1c1ee
64937
66260
  //# sourceMappingURL=bundle.js.map