@jingyi0605/codingns4dsh 0.2.1-beta.14 → 0.2.1-beta.15

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 (216) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +3 -3
  3. package/data/build/dist/client/bundle.js +1275 -482
  4. package/data/build/dist/client/bundle.js.map +1 -1
  5. package/data/build/dist/client/client.native-workspace-store.js +57 -1
  6. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  7. package/data/build/dist/client/client.transport.js +42 -4
  8. package/data/build/dist/client/client.transport.js.map +1 -1
  9. package/data/build/dist/client/desktop-assistant.js +42 -4
  10. package/data/build/dist/client/features/cli-adapters.js +1 -1
  11. package/data/build/dist/client/features/cli-adapters.js.map +1 -1
  12. package/data/build/dist/client/features/file-management.d.ts.map +1 -1
  13. package/data/build/dist/client/features/file-management.js +16 -0
  14. package/data/build/dist/client/features/file-management.js.map +1 -1
  15. package/data/build/dist/client/features/lan-access-panel.d.ts.map +1 -1
  16. package/data/build/dist/client/features/lan-access-panel.js +1 -0
  17. package/data/build/dist/client/features/lan-access-panel.js.map +1 -1
  18. package/data/build/dist/client/features/peer-host.d.ts.map +1 -1
  19. package/data/build/dist/client/features/peer-host.js +3 -0
  20. package/data/build/dist/client/features/peer-host.js.map +1 -1
  21. package/data/build/dist/client/features/session-translation.js +2 -2
  22. package/data/build/dist/client/features/session-translation.js.map +1 -1
  23. package/data/build/dist/client/file-management-dom.d.ts +20 -1
  24. package/data/build/dist/client/file-management-dom.d.ts.map +1 -1
  25. package/data/build/dist/client/file-management-dom.js +94 -18
  26. package/data/build/dist/client/file-management-dom.js.map +1 -1
  27. package/data/build/dist/client/file-viewer-copy-path-menu.d.ts +27 -0
  28. package/data/build/dist/client/file-viewer-copy-path-menu.d.ts.map +1 -0
  29. package/data/build/dist/client/file-viewer-copy-path-menu.js +101 -0
  30. package/data/build/dist/client/file-viewer-copy-path-menu.js.map +1 -0
  31. package/data/build/dist/client/git-management-settings.d.ts +4 -0
  32. package/data/build/dist/client/git-management-settings.d.ts.map +1 -0
  33. package/data/build/dist/client/git-management-settings.js +73 -0
  34. package/data/build/dist/client/git-management-settings.js.map +1 -0
  35. package/data/build/dist/client/git-management.d.ts +2 -1
  36. package/data/build/dist/client/git-management.d.ts.map +1 -1
  37. package/data/build/dist/client/git-management.js +47 -7
  38. package/data/build/dist/client/git-management.js.map +1 -1
  39. package/data/build/dist/client/locale.js +2 -2
  40. package/data/build/dist/client/locale.js.map +1 -1
  41. package/data/build/dist/client/locales/git.d.ts.map +1 -1
  42. package/data/build/dist/client/locales/git.js +30 -2
  43. package/data/build/dist/client/locales/git.js.map +1 -1
  44. package/data/build/dist/client/locales/peerHost.d.ts.map +1 -1
  45. package/data/build/dist/client/locales/peerHost.js +2 -0
  46. package/data/build/dist/client/locales/peerHost.js.map +1 -1
  47. package/data/build/dist/client/locales/quickApps.d.ts +4 -0
  48. package/data/build/dist/client/locales/quickApps.d.ts.map +1 -1
  49. package/data/build/dist/client/locales/quickApps.js +8 -0
  50. package/data/build/dist/client/locales/quickApps.js.map +1 -1
  51. package/data/build/dist/client/model-priority-pool.d.ts +23 -0
  52. package/data/build/dist/client/model-priority-pool.d.ts.map +1 -0
  53. package/data/build/dist/client/{session-translation-model-pool.js → model-priority-pool.js} +8 -9
  54. package/data/build/dist/client/model-priority-pool.js.map +1 -0
  55. package/data/build/dist/client/quick-apps/client.js +2 -2
  56. package/data/build/dist/client/quick-apps/client.js.map +1 -1
  57. package/data/build/dist/client/quick-apps/launcher.d.ts.map +1 -1
  58. package/data/build/dist/client/quick-apps/launcher.js +21 -6
  59. package/data/build/dist/client/quick-apps/launcher.js.map +1 -1
  60. package/data/build/dist/client/quick-apps/presentation.d.ts.map +1 -1
  61. package/data/build/dist/client/quick-apps/presentation.js +18 -2
  62. package/data/build/dist/client/quick-apps/presentation.js.map +1 -1
  63. package/data/build/dist/client/quick-apps/rail-preference.d.ts +5 -0
  64. package/data/build/dist/client/quick-apps/rail-preference.d.ts.map +1 -0
  65. package/data/build/dist/client/quick-apps/rail-preference.js +19 -0
  66. package/data/build/dist/client/quick-apps/rail-preference.js.map +1 -0
  67. package/data/build/dist/client/quick-apps/styles.d.ts.map +1 -1
  68. package/data/build/dist/client/quick-apps/styles.js +12 -2
  69. package/data/build/dist/client/quick-apps/styles.js.map +1 -1
  70. package/data/build/dist/client/quick-apps/viewer.d.ts.map +1 -1
  71. package/data/build/dist/client/quick-apps/viewer.js +1 -1
  72. package/data/build/dist/client/quick-apps/viewer.js.map +1 -1
  73. package/data/build/dist/client/workspace-session-visibility-dom.d.ts.map +1 -1
  74. package/data/build/dist/client/workspace-session-visibility-dom.js +38 -6
  75. package/data/build/dist/client/workspace-session-visibility-dom.js.map +1 -1
  76. package/data/build/dist/dsh-capabilities/client/composer-presentation-adapter.d.ts +8 -0
  77. package/data/build/dist/dsh-capabilities/client/composer-presentation-adapter.d.ts.map +1 -0
  78. package/data/build/dist/dsh-capabilities/client/composer-presentation-adapter.js +71 -0
  79. package/data/build/dist/dsh-capabilities/client/composer-presentation-adapter.js.map +1 -0
  80. package/data/build/dist/dsh-capabilities/client/peer-host-attachment-adapter.d.ts +3 -0
  81. package/data/build/dist/dsh-capabilities/client/peer-host-attachment-adapter.d.ts.map +1 -0
  82. package/data/build/dist/dsh-capabilities/client/peer-host-attachment-adapter.js +27 -0
  83. package/data/build/dist/dsh-capabilities/client/peer-host-attachment-adapter.js.map +1 -0
  84. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.d.ts +2 -1
  85. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.d.ts.map +1 -1
  86. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.js +22 -47
  87. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.js.map +1 -1
  88. package/data/build/dist/dsh-capabilities/host/quick-app-proxy-provider.js +1 -1
  89. package/data/build/dist/dsh-capabilities/host/quick-app-proxy-provider.js.map +1 -1
  90. package/data/build/dist/dsh-capabilities/matrix.js +1 -1
  91. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  92. package/data/build/dist/host/cli-adapters/command-code-driver.js +2 -1
  93. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  94. package/data/build/dist/host/cli-adapters/dsh-tool-history.js +3 -2
  95. package/data/build/dist/host/cli-adapters/dsh-tool-history.js.map +1 -1
  96. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  97. package/data/build/dist/host/cli-adapters/feature.js +4 -0
  98. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  99. package/data/build/dist/host/cli-adapters/grok-driver.js +16 -3
  100. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  101. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js +3 -1
  102. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js.map +1 -1
  103. package/data/build/dist/host/cli-adapters/pi-driver.d.ts.map +1 -1
  104. package/data/build/dist/host/cli-adapters/pi-driver.js +44 -10
  105. package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
  106. package/data/build/dist/host/cli-bridge/bridge-server.d.ts +2 -0
  107. package/data/build/dist/host/cli-bridge/bridge-server.d.ts.map +1 -1
  108. package/data/build/dist/host/cli-bridge/bridge-server.js +30 -3
  109. package/data/build/dist/host/cli-bridge/bridge-server.js.map +1 -1
  110. package/data/build/dist/host/cli-bridge/command-code-mod.d.ts.map +1 -1
  111. package/data/build/dist/host/cli-bridge/command-code-mod.js +43 -0
  112. package/data/build/dist/host/cli-bridge/command-code-mod.js.map +1 -1
  113. package/data/build/dist/host/cli-bridge/injections.d.ts +8 -0
  114. package/data/build/dist/host/cli-bridge/injections.d.ts.map +1 -1
  115. package/data/build/dist/host/cli-bridge/injections.js +41 -2
  116. package/data/build/dist/host/cli-bridge/injections.js.map +1 -1
  117. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.d.ts +1 -1
  118. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js +42 -4
  119. package/data/build/dist/host/cli-bridge/mcp-stdio-entry.js.map +1 -1
  120. package/data/build/dist/host/cli-bridge/pi-extension-entry.d.ts +3 -0
  121. package/data/build/dist/host/cli-bridge/pi-extension-entry.d.ts.map +1 -0
  122. package/data/build/dist/host/cli-bridge/pi-extension-entry.js +9 -0
  123. package/data/build/dist/host/cli-bridge/pi-extension-entry.js.map +1 -0
  124. package/data/build/dist/host/cli-bridge/pi-extension.d.ts +52 -0
  125. package/data/build/dist/host/cli-bridge/pi-extension.d.ts.map +1 -0
  126. package/data/build/dist/host/cli-bridge/pi-extension.js +273 -0
  127. package/data/build/dist/host/cli-bridge/pi-extension.js.map +1 -0
  128. package/data/build/dist/host/cli-bridge/search-dispatch.d.ts +20 -0
  129. package/data/build/dist/host/cli-bridge/search-dispatch.d.ts.map +1 -0
  130. package/data/build/dist/host/cli-bridge/search-dispatch.js +61 -0
  131. package/data/build/dist/host/cli-bridge/search-dispatch.js.map +1 -0
  132. package/data/build/dist/host/cli-bridge/team-adapters.d.ts +1 -1
  133. package/data/build/dist/host/cli-bridge/team-adapters.d.ts.map +1 -1
  134. package/data/build/dist/host/cli-bridge/team-adapters.js +1 -0
  135. package/data/build/dist/host/cli-bridge/team-adapters.js.map +1 -1
  136. package/data/build/dist/host/features/file-management.d.ts.map +1 -1
  137. package/data/build/dist/host/features/file-management.js +2 -1
  138. package/data/build/dist/host/features/file-management.js.map +1 -1
  139. package/data/build/dist/host/features/git-commit-message.d.ts +5 -0
  140. package/data/build/dist/host/features/git-commit-message.d.ts.map +1 -0
  141. package/data/build/dist/host/features/git-commit-message.js +66 -0
  142. package/data/build/dist/host/features/git-commit-message.js.map +1 -0
  143. package/data/build/dist/host/features/git-management.d.ts +11 -2
  144. package/data/build/dist/host/features/git-management.d.ts.map +1 -1
  145. package/data/build/dist/host/features/git-management.js +61 -7
  146. package/data/build/dist/host/features/git-management.js.map +1 -1
  147. package/data/build/dist/host/features/lan-access-dsh.d.ts.map +1 -1
  148. package/data/build/dist/host/features/lan-access-dsh.js +2 -2
  149. package/data/build/dist/host/features/lan-access-dsh.js.map +1 -1
  150. package/data/build/dist/host/index.d.ts.map +1 -1
  151. package/data/build/dist/host/index.js +6 -38
  152. package/data/build/dist/host/index.js.map +1 -1
  153. package/data/build/dist/host/lan-access-dsh.d.ts +9 -1
  154. package/data/build/dist/host/lan-access-dsh.d.ts.map +1 -1
  155. package/data/build/dist/host/lan-access-dsh.js +38 -11
  156. package/data/build/dist/host/lan-access-dsh.js.map +1 -1
  157. package/data/build/dist/host/modules/quick-apps/egress.d.ts +35 -0
  158. package/data/build/dist/host/modules/quick-apps/egress.d.ts.map +1 -0
  159. package/data/build/dist/host/modules/quick-apps/egress.js +244 -0
  160. package/data/build/dist/host/modules/quick-apps/egress.js.map +1 -0
  161. package/data/build/dist/host/modules/quick-apps/registry.d.ts.map +1 -1
  162. package/data/build/dist/host/modules/quick-apps/registry.js +10 -1
  163. package/data/build/dist/host/modules/quick-apps/registry.js.map +1 -1
  164. package/data/build/dist/host/modules/quick-apps/remote.js +1 -1
  165. package/data/build/dist/host/modules/quick-apps/remote.js.map +1 -1
  166. package/data/build/dist/host/modules/quick-apps/static-handler.d.ts.map +1 -1
  167. package/data/build/dist/host/modules/quick-apps/static-handler.js +29 -6
  168. package/data/build/dist/host/modules/quick-apps/static-handler.js.map +1 -1
  169. package/data/build/dist/host/rpc.js +2 -2
  170. package/data/build/dist/host/rpc.js.map +1 -1
  171. package/data/build/dist/host/session-changes.d.ts.map +1 -1
  172. package/data/build/dist/host/session-changes.js +6 -2
  173. package/data/build/dist/host/session-changes.js.map +1 -1
  174. package/data/build/dist/host/settings.d.ts.map +1 -1
  175. package/data/build/dist/host/settings.js +8 -0
  176. package/data/build/dist/host/settings.js.map +1 -1
  177. package/data/build/dist/host/workspace-root.d.ts +14 -0
  178. package/data/build/dist/host/workspace-root.d.ts.map +1 -0
  179. package/data/build/dist/host/workspace-root.js +99 -0
  180. package/data/build/dist/host/workspace-root.js.map +1 -0
  181. package/data/build/dist/shared/contracts/config.d.ts +5 -1
  182. package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
  183. package/data/build/dist/shared/contracts/config.js +3 -0
  184. package/data/build/dist/shared/contracts/config.js.map +1 -1
  185. package/data/build/dist/shared/contracts/git.d.ts +17 -0
  186. package/data/build/dist/shared/contracts/git.d.ts.map +1 -1
  187. package/data/build/dist/shared/contracts/git.js +27 -1
  188. package/data/build/dist/shared/contracts/git.js.map +1 -1
  189. package/data/build/dist/shared/contracts/quick-apps.d.ts +2 -0
  190. package/data/build/dist/shared/contracts/quick-apps.d.ts.map +1 -1
  191. package/data/build/dist/shared/contracts/quick-apps.js.map +1 -1
  192. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  193. package/data/build/dist/shared/contracts/version.js +1 -1
  194. package/data/build/dist/shared/index.d.ts +2 -1
  195. package/data/build/dist/shared/index.d.ts.map +1 -1
  196. package/data/build/dist/shared/index.js +2 -1
  197. package/data/build/dist/shared/index.js.map +1 -1
  198. package/data/build/dist/shared/quick-app-network-allow.d.ts +8 -0
  199. package/data/build/dist/shared/quick-app-network-allow.d.ts.map +1 -0
  200. package/data/build/dist/shared/quick-app-network-allow.js +192 -0
  201. package/data/build/dist/shared/quick-app-network-allow.js.map +1 -0
  202. package/data/build/dist/shared/quick-app-network-bootstrap.d.ts +9 -0
  203. package/data/build/dist/shared/quick-app-network-bootstrap.d.ts.map +1 -0
  204. package/data/build/dist/shared/quick-app-network-bootstrap.js +134 -0
  205. package/data/build/dist/shared/quick-app-network-bootstrap.js.map +1 -0
  206. package/data/build/dist/shared/quick-app-storage-bootstrap.d.ts.map +1 -1
  207. package/data/build/dist/shared/quick-app-storage-bootstrap.js +4 -1
  208. package/data/build/dist/shared/quick-app-storage-bootstrap.js.map +1 -1
  209. package/package.json +1 -1
  210. package/profile/README.md +2 -2
  211. package/profile/package.json +2 -2
  212. package/profile/version.json +1 -1
  213. package/version.json +1 -1
  214. package/data/build/dist/client/session-translation-model-pool.d.ts +0 -16
  215. package/data/build/dist/client/session-translation-model-pool.d.ts.map +0 -1
  216. package/data/build/dist/client/session-translation-model-pool.js.map +0 -1
@@ -8005,7 +8005,7 @@ window.__ModuleLoader__.load({
8005
8005
  return /^0\.1\.5(?:-|$)/u.test(version);
8006
8006
  }
8007
8007
  /** Codingns4DSH 插件自身的 npm 版本。 */
8008
- const CODINGNS_VERSION = "0.2.1-beta.14";
8008
+ const CODINGNS_VERSION = "0.2.1-beta.15";
8009
8009
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
8010
8010
  function isDshVersionCompatible(version) {
8011
8011
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -8063,6 +8063,36 @@ window.__ModuleLoader__.load({
8063
8063
  return 0;
8064
8064
  }
8065
8065
  //#endregion
8066
+ //#region src/shared/contracts/git.ts
8067
+ const DEFAULT_GIT_MANAGEMENT_SETTINGS = {
8068
+ commitMessageEnabled: true,
8069
+ commitMessageDetail: "concise",
8070
+ commitMessageModels: [],
8071
+ commitMessagePrompt: ""
8072
+ };
8073
+ const MAX_GIT_COMMIT_MESSAGE_CHARS = 1e4;
8074
+ const MAX_GIT_COMMIT_PROMPT_CHARS = 1e4;
8075
+ function normalizeGitManagementSettings(value) {
8076
+ const seen = /* @__PURE__ */ new Set();
8077
+ return {
8078
+ commitMessageEnabled: value?.commitMessageEnabled !== false,
8079
+ commitMessageDetail: value?.commitMessageDetail === "detailed" ? "detailed" : "concise",
8080
+ commitMessagePrompt: typeof value?.commitMessagePrompt === "string" ? value.commitMessagePrompt : "",
8081
+ commitMessageModels: (value?.commitMessageModels ?? []).flatMap((item) => {
8082
+ const provider = item?.provider?.trim();
8083
+ const model = item?.model?.trim();
8084
+ if (!provider || !model) return [];
8085
+ const key = JSON.stringify([provider, model]);
8086
+ if (seen.has(key)) return [];
8087
+ seen.add(key);
8088
+ return [{
8089
+ provider,
8090
+ model
8091
+ }];
8092
+ })
8093
+ };
8094
+ }
8095
+ //#endregion
8066
8096
  //#region src/shared/contracts/config.ts
8067
8097
  const DEFAULT_ASSISTANT_VOICE_SETTINGS = {
8068
8098
  initialized: false,
@@ -8251,6 +8281,7 @@ window.__ModuleLoader__.load({
8251
8281
  const CODINGNS_MOBILE_ACCESS_FIELD = "mobileAccess";
8252
8282
  const CODINGNS_SUBSCRIPTION_USAGE_FIELD = "subscriptionUsage";
8253
8283
  const CODINGNS_SESSION_TRANSLATION_FIELD = "sessionTranslation";
8284
+ const CODINGNS_GIT_MANAGEMENT_FIELD = "gitManagement";
8254
8285
  const CODINGNS_ASSISTANT_FIELD = "assistant";
8255
8286
  const DEFAULT_CODINGNS_CONTROL_BASE_URL = "https://channel.codingns.com:1443";
8256
8287
  const DEFAULT_CODINGNS_CONTROL_BASE_URLS = [DEFAULT_CODINGNS_CONTROL_BASE_URL];
@@ -8295,6 +8326,7 @@ window.__ModuleLoader__.load({
8295
8326
  agentAdapterPreferences: {},
8296
8327
  subagentBridge: DEFAULT_SUBAGENT_BRIDGE_SETTINGS,
8297
8328
  sessionTranslation: require_session_translation.DEFAULT_SESSION_TRANSLATION_SETTINGS,
8329
+ gitManagement: DEFAULT_GIT_MANAGEMENT_SETTINGS,
8298
8330
  terminalEnhancement: DEFAULT_TERMINAL_ENHANCEMENT_SETTINGS,
8299
8331
  workspaceSessionEnhancement: DEFAULT_WORKSPACE_SESSION_ENHANCEMENT_SETTINGS,
8300
8332
  fileManagement: DEFAULT_FILE_MANAGEMENT_SETTINGS,
@@ -8451,6 +8483,12 @@ window.__ModuleLoader__.load({
8451
8483
  return CODINGNS_FILE_MANAGEMENT_FIELD;
8452
8484
  }
8453
8485
  });
8486
+ Object.defineProperty(exports, "CODINGNS_GIT_MANAGEMENT_FIELD", {
8487
+ enumerable: true,
8488
+ get: function() {
8489
+ return CODINGNS_GIT_MANAGEMENT_FIELD;
8490
+ }
8491
+ });
8454
8492
  Object.defineProperty(exports, "CODINGNS_H5_LOGIN_URL", {
8455
8493
  enumerable: true,
8456
8494
  get: function() {
@@ -8595,6 +8633,18 @@ window.__ModuleLoader__.load({
8595
8633
  return DSH_VERSION;
8596
8634
  }
8597
8635
  });
8636
+ Object.defineProperty(exports, "MAX_GIT_COMMIT_MESSAGE_CHARS", {
8637
+ enumerable: true,
8638
+ get: function() {
8639
+ return MAX_GIT_COMMIT_MESSAGE_CHARS;
8640
+ }
8641
+ });
8642
+ Object.defineProperty(exports, "MAX_GIT_COMMIT_PROMPT_CHARS", {
8643
+ enumerable: true,
8644
+ get: function() {
8645
+ return MAX_GIT_COMMIT_PROMPT_CHARS;
8646
+ }
8647
+ });
8598
8648
  Object.defineProperty(exports, "MOBILE_VIEWPORT_MAX_PX_LIMITS", {
8599
8649
  enumerable: true,
8600
8650
  get: function() {
@@ -8667,6 +8717,12 @@ window.__ModuleLoader__.load({
8667
8717
  return minimumSupportedDshVersion;
8668
8718
  }
8669
8719
  });
8720
+ Object.defineProperty(exports, "normalizeGitManagementSettings", {
8721
+ enumerable: true,
8722
+ get: function() {
8723
+ return normalizeGitManagementSettings;
8724
+ }
8725
+ });
8670
8726
  Object.defineProperty(exports, "normalizeLanAccessDshPwaSettings", {
8671
8727
  enumerable: true,
8672
8728
  get: function() {
@@ -17897,7 +17953,21 @@ window.__ModuleLoader__.load({
17897
17953
  "git.stagingEmpty": "Staging area is empty",
17898
17954
  "git.stagedCount": "{count} staged",
17899
17955
  "git.commitPlaceholder": "Type a commit message here",
17900
- "git.draftUnavailable": "Commit message generation is not available yet",
17956
+ "git.generatingMessage": "Generating commit message…",
17957
+ "git.generationEnabled": "Generate commit messages",
17958
+ "git.generationEnabledHelp": "Show the Generate button in the Git panel to draft a message from staged changes.",
17959
+ "git.messageDetail": "Commit message level",
17960
+ "git.messageConcise": "Concise — subject only",
17961
+ "git.messageDetailed": "Detailed — subject and change summary",
17962
+ "git.messageModels": "Commit message models",
17963
+ "git.messageModelsPicker": "Add commit message models",
17964
+ "git.messageModelsHelp": "Drag to set priority; models are tried in order. An empty pool follows the default DSH model. If generation fails, your existing draft is kept.",
17965
+ "git.settingsSaved": "Git settings saved",
17966
+ "git.messagePrompt": "Git commit rule prompt",
17967
+ "git.messagePromptHelp": "Custom rules for commit-message language, style, and conventions. Leave blank to use defaults; the selected detail level still applies.",
17968
+ "git.messagePromptPlaceholder": "For example: Use Conventional Commits, include a scope, and write in English.",
17969
+ "git.messagePromptSave": "Save commit rules",
17970
+ "git.messagePromptSaving": "Saving commit rules…",
17901
17971
  "git.draftMessage": "Generate commit message",
17902
17972
  "git.commit": "Commit",
17903
17973
  "git.stagedFiles": "Staged files",
@@ -18005,7 +18075,21 @@ window.__ModuleLoader__.load({
18005
18075
  "git.stagingEmpty": "暂存区为空",
18006
18076
  "git.stagedCount": "{count} 个已暂存",
18007
18077
  "git.commitPlaceholder": "在这里输入提交信息",
18008
- "git.draftUnavailable": "生成提交信息功能暂未开放",
18078
+ "git.generatingMessage": "正在生成提交信息…",
18079
+ "git.generationEnabled": "生成 Git 提交信息",
18080
+ "git.generationEnabledHelp": "在 Git 面板显示生成按钮,根据已暂存的改动起草提交信息。",
18081
+ "git.messageDetail": "提交信息级别",
18082
+ "git.messageConcise": "简洁 — 仅标题",
18083
+ "git.messageDetailed": "详细 — 标题与变更摘要",
18084
+ "git.messageModels": "提交信息模型",
18085
+ "git.messageModelsPicker": "添加提交信息模型",
18086
+ "git.messageModelsHelp": "拖拽调整优先级,按顺序尝试模型;模型池为空时跟随 DSH 默认模型。生成失败时保留已有草稿。",
18087
+ "git.settingsSaved": "Git 设置已保存",
18088
+ "git.messagePrompt": "Git 提交规则提示词",
18089
+ "git.messagePromptHelp": "自定义提交信息的语言、风格和格式规范。留空时使用默认规则;简洁或详细级别仍然生效。",
18090
+ "git.messagePromptPlaceholder": "例如:使用 Conventional Commits 格式,包含 scope,并使用英文编写。",
18091
+ "git.messagePromptSave": "保存提交规则",
18092
+ "git.messagePromptSaving": "正在保存提交规则…",
18009
18093
  "git.draftMessage": "生成提交信息",
18010
18094
  "git.commit": "提交",
18011
18095
  "git.stagedFiles": "暂存文件",
@@ -18368,6 +18452,7 @@ window.__ModuleLoader__.load({
18368
18452
  "peerHost.fileWorkspaceUnavailable": "The remote file scope is unavailable or inconsistent. Please wait for PeerHost workspaces to refresh.",
18369
18453
  "peerHost.questionSessionUnavailable": "The session for this remote question is unavailable. Please reconnect.",
18370
18454
  "peerHost.sessionUnavailable": "The remote session scope is unavailable. Please wait for PeerHost workspaces to refresh.",
18455
+ "peerHost.attachmentFolderUnsupported": "Add individual files to the remote session; local folders cannot be attached.",
18371
18456
  "peerHost.reference.section": "Conversations",
18372
18457
  "peerHost.reference.newSession": "New session",
18373
18458
  "peerHost.stateExternal": "The Transport structure of this page is not supported, so the plugin cannot wrap it and PeerHost aggregation is disabled; refreshing the page will not change the result.",
@@ -18448,6 +18533,7 @@ window.__ModuleLoader__.load({
18448
18533
  "peerHost.fileWorkspaceUnavailable": "远程文件作用域不可用或不一致,请等待 PeerHost 工作区刷新",
18449
18534
  "peerHost.questionSessionUnavailable": "远端问题所属会话不可用,请重新连接",
18450
18535
  "peerHost.sessionUnavailable": "远端会话作用域暂不可用,请等待 PeerHost 工作区刷新",
18536
+ "peerHost.attachmentFolderUnsupported": "请向远程会话添加单个文件,不能附加本机文件夹。",
18451
18537
  "peerHost.reference.section": "对话",
18452
18538
  "peerHost.reference.newSession": "新会话",
18453
18539
  "peerHost.stateExternal": "当前页面的 Transport 结构不受支持,插件无法包装它,PeerHost 聚合已停用;刷新页面不会改变结果。",
@@ -19789,6 +19875,10 @@ window.__ModuleLoader__.load({
19789
19875
  "quickApps.kind": "Open as",
19790
19876
  "quickApps.html": "HTML application",
19791
19877
  "quickApps.text": "Text document",
19878
+ "quickApps.networkAllow": "Local addresses",
19879
+ "quickApps.networkAllowHelp": "Leave this empty to block loopback, private networks, link-local addresses, and cloud metadata. Add one local IP, CIDR range, or hostname per line, up to 16. Examples: 127.0.0.1, localhost, 192.168.1.0/24.",
19880
+ "quickApps.networkAllowPlaceholder": "127.0.0.1\nlocalhost\n192.168.1.0/24",
19881
+ "quickApps.networkAllowInvalid": "Use a local IP address, CIDR range, or hostname, with one entry per line.",
19792
19882
  "quickApps.spa": "Use the entry page for application navigation",
19793
19883
  "quickApps.pathHelp": "Enter workspace-relative paths. Use a dedicated application folder; an empty folder path selects the workspace root.",
19794
19884
  "quickApps.empty": "No shortcuts yet. In edit mode, add an HTML application or text document from a managed workspace.",
@@ -19918,6 +20008,10 @@ window.__ModuleLoader__.load({
19918
20008
  "quickApps.kind": "打开方式",
19919
20009
  "quickApps.html": "HTML 应用",
19920
20010
  "quickApps.text": "文本文档",
20011
+ "quickApps.networkAllow": "允许的本地地址",
20012
+ "quickApps.networkAllowHelp": "留空则拒绝回环、私网、链路本地和云元数据地址。每行填写一个本地 IP、CIDR 网段或主机名,最多 16 个。例如 127.0.0.1、localhost、192.168.1.0/24。",
20013
+ "quickApps.networkAllowPlaceholder": "127.0.0.1\nlocalhost\n192.168.1.0/24",
20014
+ "quickApps.networkAllowInvalid": "请逐行填写本地 IP、CIDR 网段或主机名。",
19921
20015
  "quickApps.spa": "应用内导航使用入口页面",
19922
20016
  "quickApps.pathHelp": "填写相对于工作区的路径。建议使用专用应用目录;目录留空表示工作区根目录。",
19923
20017
  "quickApps.empty": "还没有快捷方式。可在编辑模式下从受管工作区添加 HTML 应用或文本文档。",
@@ -20212,7 +20306,7 @@ window.__ModuleLoader__.load({
20212
20306
  "feature.fileManagement.label": "File management enhancements",
20213
20307
  "feature.fileManagement.description": "Add file and folder operation menus to the DSH file sidebar and edit common text files in place.",
20214
20308
  "fileManagement.menuEnhancement": "File and folder operation menu",
20215
- "fileManagement.menuEnhancementDescription": "Show the right-click operation menu for files and folders in the DSH sidebar.",
20309
+ "fileManagement.menuEnhancementDescription": "Show the right-click operation menu for files and folders in the DSH sidebar, and copy relative or absolute paths from the file viewer.",
20216
20310
  "fileManagement.fileEditor": "File viewer editor",
20217
20311
  "fileManagement.fileEditorDescription": "Show the icon button for editing supported text files with syntax highlighting and line numbers.",
20218
20312
  "fileManagement.sessionChangedFiles": "Show current session changed files",
@@ -20665,7 +20759,7 @@ window.__ModuleLoader__.load({
20665
20759
  "feature.fileManagement.label": "文件管理增强",
20666
20760
  "feature.fileManagement.description": "增强文件侧栏操作",
20667
20761
  "fileManagement.menuEnhancement": "文件管理菜单增强",
20668
- "fileManagement.menuEnhancementDescription": "在 DSH 文件侧栏为文件和目录显示右键操作菜单。",
20762
+ "fileManagement.menuEnhancementDescription": "在 DSH 文件侧栏为文件和目录显示右键操作菜单,并在文件查看器中复制相对路径或绝对路径。",
20669
20763
  "fileManagement.fileEditor": "文件查看器编辑功能",
20670
20764
  "fileManagement.fileEditorDescription": "为支持的文本文件显示编辑图标按钮,并保留语法高亮和行号。",
20671
20765
  "fileManagement.sessionChangedFiles": "显示当前会话修改的文件",
@@ -22633,6 +22727,11 @@ window.__ModuleLoader__.load({
22633
22727
  setCopiedUrl(null);
22634
22728
  setDshPort(String(current.dshPort));
22635
22729
  setListenPort(String(current.listenPort));
22730
+ setSavedSettings((prev) => prev === void 0 ? prev : {
22731
+ ...prev,
22732
+ dshPort: current.dshPort,
22733
+ listenPort: current.listenPort
22734
+ });
22636
22735
  const url = buildLanAccessUrls(current, interfaceAddresses)[0] ?? `http://${current.listenHost}:${current.actualListenPort ?? current.listenPort}/`;
22637
22736
  notify({
22638
22737
  kind: "success",
@@ -29093,6 +29192,76 @@ window.__ModuleLoader__.load({
29093
29192
  return `:is([data-slot="${name}"],[data-slot="${contextComposerSlotName(name)}"])`;
29094
29193
  }
29095
29194
  //#endregion
29195
+ //#region src/dsh-capabilities/client/composer-presentation-adapter.ts
29196
+ const presentations = /* @__PURE__ */ new WeakMap();
29197
+ /** Compose customizations over one native composer, sharing its child-slot mirror. */
29198
+ function installComposerPresentation(owner, slots, decorate, element, hooks) {
29199
+ const { useMemo, useSyncExternalStore } = hooks;
29200
+ let presentation = presentations.get(owner);
29201
+ if (presentation === void 0) {
29202
+ const state = {
29203
+ decorators: [decorate],
29204
+ listeners: /* @__PURE__ */ new Set(),
29205
+ dispose: () => void 0
29206
+ };
29207
+ const subscribe = (listener) => {
29208
+ state.listeners.add(listener);
29209
+ return () => {
29210
+ state.listeners.delete(listener);
29211
+ };
29212
+ };
29213
+ const snapshot = () => state.decorators;
29214
+ state.dispose = followPresentationEntry(slots, "conversation.composer.bar", (entry) => entry.children?.["conversation.composer.dock"] !== void 0, (native) => {
29215
+ const names = Object.fromEntries(Object.keys(native.children ?? {}).map((name) => [name, contextComposerSlotName(name)]));
29216
+ const removers = [];
29217
+ const remove = slots.register({
29218
+ name: "conversation.composer.bar",
29219
+ ...native.options,
29220
+ priority: (native.options.priority ?? 0) - 1,
29221
+ locale: native.locale,
29222
+ inject: native.inject,
29223
+ store: native.store,
29224
+ select: native.select,
29225
+ children: Object.fromEntries(Object.entries(native.children ?? {}).map(([name, spec]) => [names[name], spec]))
29226
+ }, (props) => {
29227
+ const decorators = useSyncExternalStore(subscribe, snapshot, snapshot);
29228
+ return element(useMemo(() => decorators.reduceRight((component, wrapper) => wrapper(component), native.component), [decorators]), {
29229
+ ...props,
29230
+ renderSlot: (name, ...args) => props.renderSlot(names[name] ?? name, ...args),
29231
+ ...props.renderSlotChain === void 0 ? {} : { renderSlotChain: (name, ...args) => props.renderSlotChain(names[name] ?? name, ...args) }
29232
+ });
29233
+ });
29234
+ try {
29235
+ for (const [source, target] of Object.entries(names)) removers.push(mirrorPresentationSlot(slots, source, target, element));
29236
+ } catch (error) {
29237
+ for (const dispose of removers.reverse()) dispose();
29238
+ remove();
29239
+ throw error;
29240
+ }
29241
+ return () => {
29242
+ for (const dispose of removers.reverse()) dispose();
29243
+ remove();
29244
+ };
29245
+ });
29246
+ presentation = state;
29247
+ presentations.set(owner, state);
29248
+ } else {
29249
+ presentation.decorators = [...presentation.decorators, decorate];
29250
+ for (const listener of presentation.listeners) listener();
29251
+ }
29252
+ const state = presentation;
29253
+ let disposed = false;
29254
+ return () => {
29255
+ if (disposed) return;
29256
+ disposed = true;
29257
+ state.decorators = state.decorators.filter((wrapper) => wrapper !== decorate);
29258
+ if (state.decorators.length === 0) {
29259
+ state.dispose();
29260
+ presentations.delete(owner);
29261
+ } else for (const listener of state.listeners) listener();
29262
+ };
29263
+ }
29264
+ //#endregion
29096
29265
  //#region src/dsh-capabilities/client/session-performance-adapter.ts
29097
29266
  function supportsSessionPerformancePresentation(context) {
29098
29267
  const slots = context?.slots;
@@ -29106,7 +29275,7 @@ window.__ModuleLoader__.load({
29106
29275
  /** Reuse the native activity pill, dialog, localization, settings, and session binding. */
29107
29276
  function createSessionPerformancePresentation(context) {
29108
29277
  const slots = context.slots;
29109
- return { install(useAdapter, element) {
29278
+ return { install(useAdapter, element, hooks) {
29110
29279
  const wrappers = /* @__PURE__ */ new Set();
29111
29280
  const removeActivity = followPresentationEntry(slots, "conversation.composer.dock", (entry) => entry.options.id === "activity" && !wrappers.has(entry.component), (native) => {
29112
29281
  const Activity = native.component;
@@ -29147,7 +29316,7 @@ window.__ModuleLoader__.load({
29147
29316
  };
29148
29317
  });
29149
29318
  try {
29150
- const removeContext = installGrokContextPresentation(slots, useAdapter, element);
29319
+ const removeContext = installGrokContextPresentation(context, slots, useAdapter, element, hooks);
29151
29320
  return () => {
29152
29321
  removeContext();
29153
29322
  removeActivity();
@@ -29159,48 +29328,22 @@ window.__ModuleLoader__.load({
29159
29328
  } };
29160
29329
  }
29161
29330
  /** ContextMeter lives inside the native composer bar, rather than in its own slot. */
29162
- function installGrokContextPresentation(slots, useAdapter, element) {
29163
- return followPresentationEntry(slots, "conversation.composer.bar", (entry) => entry.children?.["conversation.composer.dock"] !== void 0, (native) => {
29164
- const names = Object.fromEntries(Object.keys(native.children ?? {}).map((name) => [name, contextComposerSlotName(name)]));
29165
- const removers = [];
29166
- const remove = slots.register({
29167
- name: "conversation.composer.bar",
29168
- ...native.options,
29169
- priority: (native.options.priority ?? 0) - 1,
29170
- locale: native.locale,
29171
- inject: native.inject,
29172
- store: native.store,
29173
- select: native.select,
29174
- children: Object.fromEntries(Object.entries(native.children ?? {}).map(([name, spec]) => [names[name], spec]))
29175
- }, (props) => {
29176
- const adapter = useAdapter(props.sessionId ?? "");
29177
- return element(native.component, {
29178
- ...props,
29179
- renderSlot: (name, ...args) => props.renderSlot(names[name] ?? name, ...args),
29180
- ...props.renderSlotChain === void 0 ? {} : { renderSlotChain: (name, ...args) => props.renderSlotChain(names[name] ?? name, ...args) },
29181
- useProjection: (key, ...args) => {
29182
- const original = props.useProjection(key, ...args);
29183
- if (key === "contextBreakdown" && adapter === "grok") return void 0;
29184
- if (key !== "contextPressure") return original;
29185
- const value = props.useProjection(GROK_CONTEXT_PROJECTION);
29186
- if (adapter !== "grok") return original;
29187
- const pressure = value ?? {};
29188
- return typeof args[0] === "function" ? args[0](pressure) : pressure;
29189
- }
29190
- });
29331
+ function installGrokContextPresentation(owner, slots, useAdapter, element, hooks) {
29332
+ return installComposerPresentation(owner, slots, (Native) => function ComposerWithGrokContext(props) {
29333
+ const adapter = useAdapter(props.sessionId ?? "");
29334
+ return element(Native, {
29335
+ ...props,
29336
+ useProjection: (key, ...args) => {
29337
+ const original = props.useProjection(key, ...args);
29338
+ if (key === "contextBreakdown" && adapter === "grok") return void 0;
29339
+ if (key !== "contextPressure") return original;
29340
+ const value = props.useProjection(GROK_CONTEXT_PROJECTION);
29341
+ if (adapter !== "grok") return original;
29342
+ const pressure = value ?? {};
29343
+ return typeof args[0] === "function" ? args[0](pressure) : pressure;
29344
+ }
29191
29345
  });
29192
- try {
29193
- for (const [source, target] of Object.entries(names)) removers.push(mirrorPresentationSlot(slots, source, target, element));
29194
- } catch (error) {
29195
- for (const dispose of removers.reverse()) dispose();
29196
- remove();
29197
- throw error;
29198
- }
29199
- return () => {
29200
- for (const dispose of removers.reverse()) dispose();
29201
- remove();
29202
- };
29203
- });
29346
+ }, element, hooks);
29204
29347
  }
29205
29348
  //#endregion
29206
29349
  //#region src/dsh-capabilities/host/agent-team-adapter.ts
@@ -31329,7 +31472,10 @@ window.__ModuleLoader__.load({
31329
31472
  const uiContext = context.services.uiContext;
31330
31473
  if (uiContext !== void 0) {
31331
31474
  const performance = createDshCapabilityRegistry(context.services.dshVersion, "client", uiContext).getProfile(uiContext).capabilities.get("session.external-performance")?.value;
31332
- if (performance !== void 0) context.resources.add(performance.install((sessionId) => (0, react.useSyncExternalStore)(subscribeSessionAdapters, () => sessionAdapterId(sessionId), () => sessionAdapterId(sessionId)), react.createElement));
31475
+ if (performance !== void 0) context.resources.add(performance.install((sessionId) => (0, react.useSyncExternalStore)(subscribeSessionAdapters, () => sessionAdapterId(sessionId), () => sessionAdapterId(sessionId)), react.createElement, {
31476
+ useMemo: react.useMemo,
31477
+ useSyncExternalStore: react.useSyncExternalStore
31478
+ }));
31333
31479
  const { registerDelegateCommand } = await require.async("./client.delegate-command.js");
31334
31480
  context.resources.add(registerDelegateCommand(uiContext, {
31335
31481
  rpc: context.services.rpc,
@@ -33289,6 +33435,8 @@ window.__ModuleLoader__.load({
33289
33435
  const MENU_ATTRIBUTE$1 = "aria-haspopup";
33290
33436
  const WORKSPACE_MENU_PATTERN = /(?:更多|菜单|选项|操作|more|menu|option|action)/iu;
33291
33437
  const WORKSPACE_FILTER_PATTERN = /(?:视图选项|筛选选项|筛选会话|分组方式|排序方式|view\s*options?|filter\s*(?:options?|sessions?)|group\s*by|sort\s*by)/iu;
33438
+ /** 标题栏上的筛选按钮文案。菜单行里的“分组方式 / Group by”不能算作这个按钮。 */
33439
+ const WORKSPACE_FILTER_TOOLBAR_PATTERN = /(?:视图选项|筛选选项|view\s*options?|filter\s*options?)/iu;
33292
33440
  /**
33293
33441
  * 给原生工作区菜单增加隐藏动作,并通过工作区筛选菜单控制恢复列表。
33294
33442
  *
@@ -33381,8 +33529,9 @@ window.__ModuleLoader__.load({
33381
33529
  });
33382
33530
  const menus = findWorkspaceMenus(dom);
33383
33531
  knownNativeMenus = new Set(menus);
33532
+ removeStrayFilterActions(dom);
33384
33533
  const menuContextFresh = menuContextPending;
33385
- if (menus.length > 0) menuContextPending = false;
33534
+ if (menus.some(isVisibleMenu)) menuContextPending = false;
33386
33535
  const currentMenu = [...menus].reverse().find(isVisibleMenu);
33387
33536
  const currentMenuKind = currentMenu === void 0 ? activeMenuKind : isWorkspaceFilterMenu(currentMenu) ? "filter" : "workspace";
33388
33537
  const filterContextFresh = menuContextFresh && activeMenuKind === "filter";
@@ -33500,6 +33649,17 @@ window.__ModuleLoader__.load({
33500
33649
  const label = `${element.textContent ?? ""} ${element.getAttribute("aria-label") ?? ""} ${element.title}`.replace(/\s+/gu, " ");
33501
33650
  return WORKSPACE_FILTER_PATTERN.test(label);
33502
33651
  }
33652
+ /**
33653
+ * 筛选按钮和它的提示文字都在标题行里。标题行、操作按钮栏因此也会带上
33654
+ * “视图选项”,但不能把它们当成展开后的筛选菜单。
33655
+ */
33656
+ function containsFilterTrigger(element) {
33657
+ return [...element.querySelectorAll("button,[role=\"button\"]")].some((button) => {
33658
+ if (button.getAttribute("role") === "menuitem" || button.getAttribute("role") === "menuitemcheckbox") return false;
33659
+ const label = `${button.textContent ?? ""} ${button.getAttribute("aria-label") ?? ""} ${button.title}`.replace(/\s+/gu, " ");
33660
+ return WORKSPACE_FILTER_TOOLBAR_PATTERN.test(label);
33661
+ });
33662
+ }
33503
33663
  function findWorkspaceMenus(dom) {
33504
33664
  const explicit = [...dom.querySelectorAll("[role=\"menu\"], [role=\"listbox\"], [data-menu-content], [data-radix-menu-content]")];
33505
33665
  if (explicit.length > 0) return explicit;
@@ -33509,7 +33669,7 @@ window.__ModuleLoader__.load({
33509
33669
  let current = item.parentElement;
33510
33670
  for (let depth = 0; depth < 8 && current !== null; depth += 1, current = current.parentElement) counts.set(current, (counts.get(current) ?? 0) + 1);
33511
33671
  }
33512
- const candidates = [...counts.keys()].filter((element) => (counts.get(element) ?? 0) >= 3 && isWorkspaceFilterMenu(element));
33672
+ const candidates = [...counts.keys()].filter((element) => (counts.get(element) ?? 0) >= 3 && isWorkspaceFilterMenu(element) && !containsFilterTrigger(element));
33513
33673
  return candidates.filter((element) => !candidates.some((other) => other !== element && element.contains(other)));
33514
33674
  }
33515
33675
  /**
@@ -33518,12 +33678,12 @@ window.__ModuleLoader__.load({
33518
33678
  */
33519
33679
  function selectFilterMenus(menus, menuWorkspaceIds, activeWorkspaceId, allowUnidentified) {
33520
33680
  const visible = menus.filter(isVisibleMenu);
33521
- const candidates = visible.filter(isWorkspaceFilterMenu);
33681
+ const candidates = visible.filter((menu) => isWorkspaceFilterMenu(menu) && !containsFilterTrigger(menu));
33522
33682
  const owned = candidates.filter((menu) => menu.querySelector(`[${WORKSPACE_SESSION_HIDDEN_FILTER_ATTRIBUTE}]`) !== null);
33523
33683
  if (owned.length > 0) return [owned[owned.length - 1]];
33524
33684
  if (allowUnidentified && candidates.length > 0) return [candidates[candidates.length - 1]];
33525
33685
  if (!allowUnidentified) return [];
33526
- const fallback = visible.filter((menu) => menuWorkspaceIds.get(menu) === void 0 && (activeWorkspaceId === void 0 || resolveWorkspaceId(menu) !== activeWorkspaceId) && menu.querySelector(`[data-codingns-hidden-workspace-menu]`) === null);
33686
+ const fallback = visible.filter((menu) => !containsFilterTrigger(menu) && menuWorkspaceIds.get(menu) === void 0 && (activeWorkspaceId === void 0 || resolveWorkspaceId(menu) !== activeWorkspaceId) && menu.querySelector(`[data-codingns-hidden-workspace-menu]`) === null);
33527
33687
  return fallback.length > 0 ? [fallback[fallback.length - 1]] : [];
33528
33688
  }
33529
33689
  function selectWorkspaceMenus(menus, allowUnidentified, menuWorkspaceIds) {
@@ -33539,6 +33699,15 @@ window.__ModuleLoader__.load({
33539
33699
  const label = `${element.textContent ?? ""} ${element.getAttribute("aria-label") ?? ""} ${element.getAttribute("title") ?? ""}`;
33540
33700
  return WORKSPACE_FILTER_PATTERN.test(label);
33541
33701
  }
33702
+ /** 标题行里的副本不由 React 菜单持有,可以直接移除;菜单内的条目留给宿主卸载。 */
33703
+ function removeStrayFilterActions(dom) {
33704
+ for (const node of dom.querySelectorAll(`[${WORKSPACE_SESSION_HIDDEN_FILTER_ATTRIBUTE}]`)) {
33705
+ const host = node.parentElement;
33706
+ if (host !== null && isWorkspaceFilterMenu(host) && !containsFilterTrigger(host)) continue;
33707
+ if (node.closest("[role=\"menu\"], [role=\"listbox\"], [data-menu-content], [data-radix-menu-content]") !== null) continue;
33708
+ node.remove();
33709
+ }
33710
+ }
33542
33711
  function injectWorkspaceMenuActions(menus, dom, activeWorkspaceId, workspaceIds, menuWorkspaceIds, onHide, t) {
33543
33712
  for (const menu of menus) {
33544
33713
  for (const stale of menu.querySelectorAll(`[${WORKSPACE_SESSION_HIDDEN_FILTER_ATTRIBUTE}]`)) stale.remove();
@@ -33568,7 +33737,7 @@ window.__ModuleLoader__.load({
33568
33737
  }
33569
33738
  }
33570
33739
  function injectFilterMenuAction(dom, menus, checked, onChange, onClose, t) {
33571
- const menu = menus.find(isWorkspaceFilterMenu) ?? menus[menus.length - 1];
33740
+ const menu = menus.find((candidate) => isWorkspaceFilterMenu(candidate) && !containsFilterTrigger(candidate)) ?? [...menus].reverse().find((candidate) => !containsFilterTrigger(candidate));
33572
33741
  if (menu === void 0) return;
33573
33742
  for (const stale of menu.querySelectorAll(`[${WORKSPACE_SESSION_HIDDEN_MENU_ATTRIBUTE}]`)) stale.remove();
33574
33743
  const existing = menu.querySelector(`[${WORKSPACE_SESSION_HIDDEN_FILTER_ATTRIBUTE}]`);
@@ -34258,7 +34427,7 @@ window.__ModuleLoader__.load({
34258
34427
  * 没有 locale 服务时的静态兜底:命名空间绑定固定指向内置中文词典,
34259
34428
  * 且不产生任何语言变更通知。生产路径由 registerSubscriptionSlot 注入 DSH locale。
34260
34429
  */
34261
- const FALLBACK_LOCALE = {
34430
+ const FALLBACK_LOCALE$1 = {
34262
34431
  bind: () => require_transport.resolveCodingNsTranslator(void 0),
34263
34432
  getSnapshot: () => ({ revision: 0 }),
34264
34433
  subscribe: () => () => {},
@@ -34314,13 +34483,13 @@ window.__ModuleLoader__.load({
34314
34483
  inject: (sessionId) => ({
34315
34484
  rpc,
34316
34485
  sessionId,
34317
- locale: locale ?? FALLBACK_LOCALE,
34486
+ locale: locale ?? FALLBACK_LOCALE$1,
34318
34487
  ...getRefreshIntervalMins === void 0 ? {} : { getRefreshIntervalMins }
34319
34488
  })
34320
34489
  }, CommandCodeSubscriptionSlot));
34321
34490
  }
34322
34491
  function CommandCodeSubscriptionSlot(props) {
34323
- const t = require_transport.useCodingNsTranslator(props.locale ?? FALLBACK_LOCALE);
34492
+ const t = require_transport.useCodingNsTranslator(props.locale ?? FALLBACK_LOCALE$1);
34324
34493
  const subscriptionUsageCache = usageCache(props.rpc);
34325
34494
  const [usage, setUsage] = (0, react.useState)(null);
34326
34495
  const [adapterId, setAdapterId] = (0, react.useState)(null);
@@ -41333,6 +41502,512 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
41333
41502
  }
41334
41503
  };
41335
41504
  //#endregion
41505
+ //#region src/client/model-priority-pool.ts
41506
+ /** The persisted pool owns priority; modal choices and drag previews remain local until confirmed. */
41507
+ function ModelPriorityPool({ models: pool, catalog, disabled, pending, t, onChange, titleKey = "translation.modelTitle", pickerTitleKey = "translation.modelPickerTitle", helpKey = "translation.modelHelp", saveRejectedKey = "translation.saveRejected" }) {
41508
+ const available = new Map((catalog?.models ?? []).filter((model) => !require_session_translation.isSessionTranslationAdapter(model.provider)).map((model) => [modelKey(model), model]));
41509
+ const pooled = new Set(pool.map(modelKey));
41510
+ const [selection, setSelection] = (0, react.useState)(null);
41511
+ const [search, setSearch] = (0, react.useState)("");
41512
+ const [saveFailed, setSaveFailed] = (0, react.useState)(false);
41513
+ const [resetOpen, setResetOpen] = (0, react.useState)(false);
41514
+ const [resetFailed, setResetFailed] = (0, react.useState)(false);
41515
+ const [preview, setPreview] = (0, react.useState)(null);
41516
+ const [announcement, setAnnouncement] = (0, react.useState)("");
41517
+ const drag = (0, react.useRef)(null);
41518
+ const list = (0, react.useRef)(null);
41519
+ const poolIdentity = JSON.stringify(pool);
41520
+ const pickerOpen = selection !== null;
41521
+ const locked = disabled || pickerOpen || resetOpen;
41522
+ const cancelDrag = () => {
41523
+ drag.current = null;
41524
+ setPreview(null);
41525
+ };
41526
+ (0, react.useEffect)(() => {
41527
+ cancelDrag();
41528
+ }, [disabled, poolIdentity]);
41529
+ (0, react.useEffect)(() => {
41530
+ if (disabled && !pending) {
41531
+ setSelection(null);
41532
+ setResetOpen(false);
41533
+ }
41534
+ }, [disabled, pending]);
41535
+ const candidates = [...available.values()].filter((model) => !pooled.has(modelKey(model)));
41536
+ const query = search.trim().toLowerCase();
41537
+ const filtered = candidates.filter((model) => `${model.label} ${model.provider} ${model.model}`.toLowerCase().includes(query));
41538
+ const additions = [...selection ?? []].flatMap((key) => {
41539
+ const model = available.get(key);
41540
+ return model === void 0 || pooled.has(key) ? [] : [{
41541
+ provider: model.provider,
41542
+ model: model.model
41543
+ }];
41544
+ });
41545
+ const closePicker = () => {
41546
+ if (!pending) setSelection(null);
41547
+ };
41548
+ const addSelected = async () => {
41549
+ if (disabled || additions.length === 0) return;
41550
+ setSaveFailed(false);
41551
+ if (await onChange([...pool, ...additions])) setSelection(null);
41552
+ else setSaveFailed(true);
41553
+ };
41554
+ const closeReset = () => {
41555
+ if (!pending) setResetOpen(false);
41556
+ };
41557
+ const confirmReset = async () => {
41558
+ if (disabled || !resetOpen) return;
41559
+ setResetFailed(false);
41560
+ if (await onChange([])) setResetOpen(false);
41561
+ else setResetFailed(true);
41562
+ };
41563
+ const commitOrder = (order, key) => {
41564
+ if (locked) return;
41565
+ onChange(order).then((saved) => {
41566
+ if (saved) setAnnouncement(t("translation.modelReordered", {
41567
+ model: available.get(key)?.label ?? order.find((model) => modelKey(model) === key)?.model ?? "",
41568
+ priority: order.findIndex((model) => modelKey(model) === key) + 1
41569
+ }));
41570
+ });
41571
+ };
41572
+ const startDrag = (event, key) => {
41573
+ if (locked || pool.length < 2 || event.button !== 0 || list.current === null) return;
41574
+ event.preventDefault();
41575
+ event.currentTarget.focus();
41576
+ list.current.setPointerCapture(event.pointerId);
41577
+ drag.current = {
41578
+ pointerId: event.pointerId,
41579
+ key,
41580
+ startY: event.clientY,
41581
+ original: pool,
41582
+ order: pool
41583
+ };
41584
+ };
41585
+ const rowAtPointer = (event) => {
41586
+ const target = event.currentTarget.ownerDocument.elementFromPoint(event.clientX, event.clientY)?.closest("[data-codingns-translation-model-key]");
41587
+ return target !== null && target !== void 0 && list.current?.contains(target) ? target : void 0;
41588
+ };
41589
+ const moveDrag = (event) => {
41590
+ const current = drag.current;
41591
+ const root = list.current;
41592
+ if (locked || current === null || current.pointerId !== event.pointerId || root === null) return;
41593
+ if (preview === null && Math.abs(event.clientY - current.startY) < 4) return;
41594
+ event.preventDefault();
41595
+ const rect = root.getBoundingClientRect();
41596
+ if (event.clientY < rect.top + 24) root.scrollTop -= 12;
41597
+ else if (event.clientY > rect.bottom - 24) root.scrollTop += 12;
41598
+ const target = rowAtPointer(event);
41599
+ if (target === void 0) return;
41600
+ const targetIndex = current.order.findIndex((model) => modelKey(model) === target.dataset.codingnsTranslationModelKey);
41601
+ const sourceIndex = current.order.findIndex((model) => modelKey(model) === current.key);
41602
+ if (targetIndex < 0 || sourceIndex < 0 || targetIndex === sourceIndex) return;
41603
+ const next = {
41604
+ ...current,
41605
+ order: moveModel(current.order, sourceIndex, targetIndex)
41606
+ };
41607
+ drag.current = next;
41608
+ setPreview(next);
41609
+ };
41610
+ const finishDrag = (event) => {
41611
+ const current = drag.current;
41612
+ if (current === null || current.pointerId !== event.pointerId) return;
41613
+ cancelDrag();
41614
+ if (!locked && rowAtPointer(event) !== void 0 && JSON.stringify(current.order) !== JSON.stringify(current.original)) commitOrder(current.order, current.key);
41615
+ };
41616
+ const keyboardMove = (event, key) => {
41617
+ if (event.key === "Escape" && drag.current !== null) {
41618
+ event.stopPropagation();
41619
+ cancelDrag();
41620
+ return;
41621
+ }
41622
+ if (locked || drag.current !== null || ![
41623
+ "ArrowUp",
41624
+ "ArrowDown",
41625
+ "Home",
41626
+ "End"
41627
+ ].includes(event.key)) return;
41628
+ event.preventDefault();
41629
+ const index = pool.findIndex((model) => modelKey(model) === key);
41630
+ const target = event.key === "Home" ? 0 : event.key === "End" ? pool.length - 1 : index + (event.key === "ArrowUp" ? -1 : 1);
41631
+ if (index >= 0 && target >= 0 && target < pool.length && target !== index) commitOrder(moveModel(pool, index, target), key);
41632
+ };
41633
+ return (0, react.createElement)("div", {
41634
+ className: "codingns-translation-pool",
41635
+ "aria-busy": pending
41636
+ }, (0, react.createElement)("style", null, modelPoolCss), (0, react.createElement)("div", { className: "codingns-translation-pool-toolbar" }, (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, t(pool.length === 0 ? "translation.modelDefaultActive" : "translation.modelPoolCount", { count: pool.length })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41637
+ type: "button",
41638
+ variant: "outline",
41639
+ size: "sm",
41640
+ disabled: disabled || resetOpen,
41641
+ icon: (0, react.createElement)(require_primitives_adapter.resolvePlusIcon(), { size: 14 }),
41642
+ "aria-haspopup": "dialog",
41643
+ "aria-expanded": pickerOpen,
41644
+ onClick: () => {
41645
+ if (!disabled && !resetOpen) {
41646
+ setSearch("");
41647
+ setSaveFailed(false);
41648
+ setSelection(/* @__PURE__ */ new Set());
41649
+ }
41650
+ }
41651
+ }, t("translation.modelAdd"))), pool.length === 0 ? (0, react.createElement)("div", { className: "codingns-translation-pool-empty" }, (0, react.createElement)(require_primitives_adapter.resolveDataIcon(), { size: 22 }), (0, react.createElement)("span", null, t("translation.modelPoolEmpty"))) : (0, react.createElement)("ol", {
41652
+ ref: list,
41653
+ className: "codingns-translation-pool-list",
41654
+ "aria-label": t(titleKey),
41655
+ onPointerMove: moveDrag,
41656
+ onPointerUp: finishDrag,
41657
+ onPointerCancel: cancelDrag,
41658
+ onLostPointerCapture: cancelDrag
41659
+ }, ...(preview?.order ?? pool).map((model, index) => {
41660
+ const key = modelKey(model);
41661
+ const entry = available.get(key);
41662
+ const label = entry?.label ?? `${model.provider} / ${model.model}`;
41663
+ return (0, react.createElement)("li", {
41664
+ key,
41665
+ "data-codingns-translation-model-key": key,
41666
+ className: `codingns-translation-pool-row${preview?.key === key ? " is-dragging" : ""}`
41667
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41668
+ type: "button",
41669
+ size: "sm",
41670
+ disabled: locked || pool.length < 2,
41671
+ className: "codingns-translation-pool-handle",
41672
+ "aria-label": t("translation.modelDrag", { model: label }),
41673
+ title: t("translation.modelDragHelp"),
41674
+ onPointerDown: (event) => startDrag(event, key),
41675
+ onKeyDown: (event) => keyboardMove(event, key)
41676
+ }, (0, react.createElement)(DragHandleIcon)), (0, react.createElement)("span", {
41677
+ className: "codingns-translation-pool-priority",
41678
+ title: t("translation.modelPriority", { priority: index + 1 })
41679
+ }, index + 1), (0, react.createElement)(ModelIdentity, {
41680
+ model,
41681
+ label,
41682
+ t
41683
+ }), catalog !== null && entry === void 0 && (0, react.createElement)("span", { className: "codingns-translation-pool-unavailable" }, t("translation.modelUnavailable")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41684
+ type: "button",
41685
+ size: "sm",
41686
+ disabled: locked,
41687
+ className: "codingns-translation-pool-remove",
41688
+ "aria-label": t("translation.modelRemove", { model: label }),
41689
+ title: t("translation.modelRemove", { model: label }),
41690
+ onClick: () => {
41691
+ if (!locked) onChange(pool.filter((item) => modelKey(item) !== key));
41692
+ }
41693
+ }, (0, react.createElement)(require_primitives_adapter.resolveAssistantControlIcon("close"), { size: 14 })));
41694
+ })), (0, react.createElement)("div", { className: "codingns-translation-pool-toolbar" }, (0, react.createElement)("span", { style: {
41695
+ ...require_theme.dshSettingsHelpStyle,
41696
+ flex: 1
41697
+ } }, t(helpKey)), pool.length > 0 && (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41698
+ type: "button",
41699
+ size: "sm",
41700
+ disabled: disabled || pickerOpen,
41701
+ style: { color: require_theme.dshThemeColor.error },
41702
+ "aria-haspopup": "dialog",
41703
+ "aria-expanded": resetOpen,
41704
+ onClick: () => {
41705
+ if (!locked) {
41706
+ setResetFailed(false);
41707
+ setResetOpen(true);
41708
+ }
41709
+ }
41710
+ }, t("translation.modelFollowDefault"))), (0, react.createElement)("span", {
41711
+ role: "status",
41712
+ "aria-live": "polite",
41713
+ className: "codingns-translation-pool-status"
41714
+ }, announcement), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
41715
+ open: pickerOpen,
41716
+ onClose: closePicker,
41717
+ title: t(pickerTitleKey),
41718
+ closeLabel: t("translation.modelCancel"),
41719
+ description: t("translation.modelPickerHelp"),
41720
+ className: "codingns-translation-model-picker",
41721
+ contentClassName: "codingns-translation-model-picker-content",
41722
+ footer: (0, react.createElement)(react.Fragment, null, (0, react.createElement)("span", {
41723
+ className: "codingns-translation-picker-count",
41724
+ "aria-live": "polite",
41725
+ style: require_theme.dshSettingsHelpStyle
41726
+ }, t("translation.modelPickerCount", { count: additions.length })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41727
+ type: "button",
41728
+ variant: "outline",
41729
+ disabled: pending,
41730
+ onClick: closePicker
41731
+ }, t("translation.modelCancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41732
+ type: "button",
41733
+ variant: "primary",
41734
+ disabled: disabled || additions.length === 0,
41735
+ onClick: () => {
41736
+ addSelected();
41737
+ }
41738
+ }, t("translation.modelAddSelected", { count: additions.length })))
41739
+ }, (0, react.createElement)("div", {
41740
+ className: "codingns-translation-picker-body",
41741
+ "aria-busy": pending
41742
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
41743
+ type: "search",
41744
+ value: search,
41745
+ placeholder: t("translation.modelSearch"),
41746
+ "aria-label": t("translation.modelSearch"),
41747
+ "data-modal-autofocus": true,
41748
+ disabled,
41749
+ onChange: (event) => setSearch(event.currentTarget.value)
41750
+ }), (0, react.createElement)("div", {
41751
+ className: "codingns-translation-picker-list",
41752
+ role: "group",
41753
+ "aria-label": t(pickerTitleKey)
41754
+ }, ...filtered.map((model) => {
41755
+ const key = modelKey(model);
41756
+ return (0, react.createElement)("div", {
41757
+ key,
41758
+ className: `codingns-translation-picker-choice${selection?.has(key) ? " is-selected" : ""}`
41759
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
41760
+ checked: selection?.has(key) === true,
41761
+ disabled,
41762
+ label: model.label,
41763
+ onChange: (checked) => {
41764
+ if (disabled) return;
41765
+ setSelection((previous) => {
41766
+ const next = new Set(previous);
41767
+ if (checked) next.add(key);
41768
+ else next.delete(key);
41769
+ return next;
41770
+ });
41771
+ }
41772
+ }), (0, react.createElement)("span", {
41773
+ className: "codingns-translation-picker-provider",
41774
+ style: require_theme.dshSettingsHelpStyle
41775
+ }, t(isOfficialProvider(model.provider) ? "translation.modelOfficial" : "translation.modelThirdParty")));
41776
+ }), filtered.length > 0 ? null : (0, react.createElement)("div", {
41777
+ className: "codingns-translation-pool-empty",
41778
+ role: "status"
41779
+ }, t(catalog === null ? "translation.modelLoading" : candidates.length > 0 ? "translation.modelNoMatches" : available.size > 0 ? "translation.modelAllAdded" : "translation.modelEmpty"))), saveFailed && (0, react.createElement)("span", {
41780
+ role: "alert",
41781
+ style: {
41782
+ ...require_theme.dshSettingsHelpStyle,
41783
+ color: require_theme.dshThemeColor.error
41784
+ }
41785
+ }, t(saveRejectedKey)))), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
41786
+ open: resetOpen,
41787
+ onClose: closeReset,
41788
+ title: t("translation.modelResetTitle"),
41789
+ closeLabel: t("translation.modelCancel"),
41790
+ description: t("translation.modelResetHelp", { count: pool.length }),
41791
+ footer: (0, react.createElement)(react.Fragment, null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41792
+ type: "button",
41793
+ variant: "outline",
41794
+ disabled: pending,
41795
+ "data-modal-autofocus": true,
41796
+ onClick: closeReset
41797
+ }, t("translation.modelCancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41798
+ type: "button",
41799
+ variant: "outline",
41800
+ disabled,
41801
+ style: { color: require_theme.dshThemeColor.error },
41802
+ onClick: () => {
41803
+ confirmReset();
41804
+ }
41805
+ }, t("translation.modelResetConfirm")))
41806
+ }, resetFailed ? (0, react.createElement)("span", {
41807
+ role: "alert",
41808
+ style: {
41809
+ ...require_theme.dshSettingsHelpStyle,
41810
+ color: require_theme.dshThemeColor.error
41811
+ }
41812
+ }, t(saveRejectedKey)) : void 0));
41813
+ }
41814
+ function modelKey(model) {
41815
+ return JSON.stringify([model.provider, model.model]);
41816
+ }
41817
+ function moveModel(pool, source, target) {
41818
+ const next = [...pool];
41819
+ const model = next.splice(source, 1)[0];
41820
+ if (model !== void 0) next.splice(target, 0, model);
41821
+ return next;
41822
+ }
41823
+ function isOfficialProvider(provider) {
41824
+ return /^(?:deepseek(?:-official)?|official-deepseek)$/iu.test(provider.trim());
41825
+ }
41826
+ function ModelIdentity({ model, label, t }) {
41827
+ const [provider, ...name] = label.split(" / ");
41828
+ return (0, react.createElement)("div", {
41829
+ className: "codingns-translation-pool-identity",
41830
+ title: label
41831
+ }, (0, react.createElement)("span", { className: "codingns-translation-pool-name" }, name.join(" / ") || model.model), (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, `${provider ?? model.provider} · ${t(isOfficialProvider(model.provider) ? "translation.modelOfficial" : "translation.modelThirdParty")}`));
41832
+ }
41833
+ function DragHandleIcon() {
41834
+ return (0, react.createElement)("svg", {
41835
+ width: 14,
41836
+ height: 18,
41837
+ viewBox: "0 0 14 18",
41838
+ fill: "currentColor",
41839
+ "aria-hidden": true,
41840
+ focusable: false
41841
+ }, ...[5, 9].flatMap((cx) => [
41842
+ 4,
41843
+ 9,
41844
+ 14
41845
+ ].map((cy) => (0, react.createElement)("circle", {
41846
+ key: `${cx}:${cy}`,
41847
+ cx,
41848
+ cy,
41849
+ r: 1
41850
+ }))));
41851
+ }
41852
+ const modelPoolCss = `
41853
+ .codingns-translation-pool{display:grid;gap:10px;min-width:0}
41854
+ .codingns-translation-pool-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}
41855
+ .codingns-translation-pool-list{list-style:none;margin:0;padding:0;max-height:352px;overflow:auto;overscroll-behavior:contain;border:.5px solid ${require_theme.dshThemeColor.menuBorder};border-radius:var(--dsw-radius-md,12px);background:${require_theme.dshThemeColor.pageBackground}}
41856
+ .codingns-translation-pool-row{display:flex;align-items:center;gap:10px;min-height:64px;padding:8px 12px 8px 6px;box-sizing:border-box}
41857
+ .codingns-translation-pool-row:not(:last-child){border-bottom:.5px solid ${require_theme.dshThemeColor.menuBorder}}
41858
+ .codingns-translation-pool-row:hover{background:${require_theme.dshThemeColor.hoverBackground}}
41859
+ .codingns-translation-pool-row.is-dragging{background:${require_theme.dshThemeColor.activeBackground};box-shadow:inset 2px 0 ${require_theme.dshThemeColor.accent}}
41860
+ .codingns-translation-pool .codingns-translation-pool-handle{width:28px;flex:0 0 28px;padding:0;touch-action:none;cursor:grab;color:${require_theme.dshThemeColor.labelTertiary}}
41861
+ .codingns-translation-pool .codingns-translation-pool-handle:active{cursor:grabbing}
41862
+ .codingns-translation-pool .codingns-translation-pool-handle:disabled{cursor:default}
41863
+ .codingns-translation-pool-priority{display:flex;align-items:center;justify-content:center;flex:0 0 24px;height:24px;border-radius:var(--dsw-radius-sm,8px);background:${require_theme.dshThemeColor.surfaceSubtle};color:${require_theme.dshThemeColor.labelSecondary};font-size:${require_theme.uiFontSize(12)};font-variant-numeric:tabular-nums}
41864
+ .codingns-translation-pool-identity{display:grid;gap:2px;min-width:0;flex:1}
41865
+ .codingns-translation-pool-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:${require_theme.dshThemeColor.labelPrimary};font-size:${require_theme.uiFontSize(13)};font-weight:500;line-height:20px}
41866
+ .codingns-translation-pool-identity>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
41867
+ .codingns-translation-pool .codingns-translation-pool-remove{flex:0 0 28px;width:28px;padding:0;color:${require_theme.dshThemeColor.labelTertiary}}
41868
+ .codingns-translation-pool-unavailable{max-width:110px;flex-shrink:0;color:${require_theme.dshThemeColor.warning};font-size:${require_theme.uiFontSize(11)};line-height:16px}
41869
+ .codingns-translation-pool-empty{display:flex;align-items:center;justify-content:center;gap:10px;padding:22px 14px;color:${require_theme.dshThemeColor.labelTertiary};background:${require_theme.dshThemeColor.surfaceSubtle};border-radius:var(--dsw-radius-md,12px);font-size:${require_theme.uiFontSize(12)};text-align:center;line-height:20px}
41870
+ .codingns-translation-pool-status{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
41871
+ .codingns-translation-model-picker{width:min(520px,100%);max-height:100%;color:${require_theme.dshThemeColor.labelPrimary}}
41872
+ .codingns-translation-model-picker-content{min-height:0;overflow:auto}
41873
+ .codingns-translation-picker-body{display:grid;gap:12px;padding-bottom:4px}
41874
+ .codingns-translation-picker-list{display:grid;gap:6px;min-height:80px;max-height:320px;overflow:auto;overscroll-behavior:contain}
41875
+ .codingns-translation-picker-choice{display:grid;gap:3px;padding:10px 12px;border:.5px solid ${require_theme.dshThemeColor.menuBorder};border-radius:var(--dsw-radius-sm,8px);background:${require_theme.dshThemeColor.pageBackground}}
41876
+ .codingns-translation-picker-choice:hover,.codingns-translation-picker-choice.is-selected{background:${require_theme.dshThemeColor.hoverBackground}}
41877
+ .codingns-translation-picker-choice>label{align-items:flex-start;gap:10px;overflow-wrap:anywhere}
41878
+ .codingns-translation-picker-choice input{margin-top:2px}
41879
+ .codingns-translation-picker-provider{padding-left:26px}
41880
+ .codingns-translation-picker-count{margin-right:auto}
41881
+ @media(max-width:480px){.codingns-translation-pool-row{gap:6px;padding-right:8px}.codingns-translation-pool-unavailable{max-width:70px}.codingns-translation-picker-choice{padding:10px}}
41882
+ `;
41883
+ //#endregion
41884
+ //#region src/client/git-management-settings.ts
41885
+ function GitManagementSettingsPanel({ services, enabled, snapshot, notify }) {
41886
+ const t = require_transport.useCodingNsTranslator(services.locale);
41887
+ const value = require_native_workspace_store.normalizeGitManagementSettings(snapshot.value?.gitManagement);
41888
+ const [saving, setSaving] = (0, react.useState)(false);
41889
+ const [promptDraft, setPromptDraft] = (0, react.useState)(null);
41890
+ const promptText = promptDraft ?? value.commitMessagePrompt;
41891
+ const savingRef = (0, react.useRef)(false);
41892
+ const [catalog, setCatalog] = (0, react.useState)(null);
41893
+ const disabled = !enabled || snapshot.status !== "ready" || !snapshot.writable || saving;
41894
+ const generationDisabled = disabled || !value.commitMessageEnabled;
41895
+ (0, react.useEffect)(() => {
41896
+ if (!enabled) return;
41897
+ const abort = new AbortController();
41898
+ services.rpc.call(require_transport.CODINGNS_RPC_CHANNEL, "git/models", {}, AbortSignal.any([abort.signal, AbortSignal.timeout(1e4)])).then((result) => {
41899
+ if (!abort.signal.aborted && result.ok) setCatalog(result.value);
41900
+ }).catch(() => void 0);
41901
+ return () => abort.abort();
41902
+ }, [services.rpc, enabled]);
41903
+ const save = async (patch) => {
41904
+ if (disabled || savingRef.current) return false;
41905
+ savingRef.current = true;
41906
+ setSaving(true);
41907
+ try {
41908
+ const next = {
41909
+ ...require_native_workspace_store.normalizeGitManagementSettings(services.settings.getSnapshot().value?.gitManagement),
41910
+ ...patch
41911
+ };
41912
+ if (!await services.settings.set("gitManagement", next)) throw new Error(t("settings.moduleWriteRejected"));
41913
+ notify({
41914
+ kind: "success",
41915
+ message: t("git.settingsSaved")
41916
+ });
41917
+ return true;
41918
+ } catch (error) {
41919
+ notify({
41920
+ kind: "error",
41921
+ message: error instanceof Error ? error.message : String(error)
41922
+ });
41923
+ return false;
41924
+ } finally {
41925
+ savingRef.current = false;
41926
+ setSaving(false);
41927
+ }
41928
+ };
41929
+ return (0, react.createElement)("div", {
41930
+ style: {
41931
+ ...require_theme.dshFormRootStyle,
41932
+ opacity: disabled ? .55 : 1,
41933
+ pointerEvents: disabled ? "none" : "auto"
41934
+ },
41935
+ "aria-disabled": disabled
41936
+ }, (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
41937
+ label: t("git.generationEnabled"),
41938
+ description: t("git.generationEnabledHelp"),
41939
+ checked: value.commitMessageEnabled,
41940
+ disabled,
41941
+ onChange: (checked) => {
41942
+ save({ commitMessageEnabled: checked });
41943
+ }
41944
+ }), (0, react.createElement)("div", {
41945
+ "aria-disabled": generationDisabled,
41946
+ style: {
41947
+ opacity: generationDisabled ? .55 : 1,
41948
+ pointerEvents: generationDisabled ? "none" : "auto"
41949
+ }
41950
+ }, (0, react.createElement)("label", { style: {
41951
+ ...require_theme.dshSettingsListRowStyle,
41952
+ flexDirection: "column",
41953
+ alignItems: "stretch",
41954
+ gap: 6
41955
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("git.messageDetail")), (0, react.createElement)("select", {
41956
+ value: value.commitMessageDetail,
41957
+ disabled: generationDisabled,
41958
+ style: require_theme.dshSettingsFieldStyle,
41959
+ onChange: (event) => {
41960
+ save({ commitMessageDetail: event.currentTarget.value === "detailed" ? "detailed" : "concise" });
41961
+ }
41962
+ }, (0, react.createElement)("option", { value: "concise" }, t("git.messageConcise")), (0, react.createElement)("option", { value: "detailed" }, t("git.messageDetailed")))), (0, react.createElement)("div", { style: {
41963
+ ...require_theme.dshSettingsFieldLabelStyle,
41964
+ margin: "12px 0 8px"
41965
+ } }, t("git.messageModels")), (0, react.createElement)(ModelPriorityPool, {
41966
+ models: value.commitMessageModels,
41967
+ catalog,
41968
+ disabled: generationDisabled,
41969
+ pending: saving,
41970
+ t,
41971
+ titleKey: "git.messageModels",
41972
+ pickerTitleKey: "git.messageModelsPicker",
41973
+ helpKey: "git.messageModelsHelp",
41974
+ saveRejectedKey: "settings.moduleWriteRejected",
41975
+ onChange: (models) => save({ commitMessageModels: models })
41976
+ }), (0, react.createElement)("div", { style: {
41977
+ display: "grid",
41978
+ gap: 6,
41979
+ marginTop: 16
41980
+ } }, (0, react.createElement)("label", { style: {
41981
+ display: "grid",
41982
+ gap: 6
41983
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("git.messagePrompt")), (0, react.createElement)("textarea", {
41984
+ rows: 5,
41985
+ value: promptText,
41986
+ maxLength: require_native_workspace_store.MAX_GIT_COMMIT_PROMPT_CHARS,
41987
+ disabled: generationDisabled,
41988
+ "aria-label": t("git.messagePrompt"),
41989
+ placeholder: t("git.messagePromptPlaceholder"),
41990
+ style: {
41991
+ ...require_theme.dshSettingsFieldStyle,
41992
+ resize: "vertical"
41993
+ },
41994
+ onChange: (event) => {
41995
+ if (!generationDisabled) setPromptDraft(event.currentTarget.value);
41996
+ }
41997
+ })), (0, react.createElement)("div", { style: require_theme.dshSettingsHelpStyle }, t("git.messagePromptHelp")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
41998
+ type: "button",
41999
+ variant: "outline",
42000
+ size: "sm",
42001
+ style: { justifySelf: "start" },
42002
+ disabled: generationDisabled || promptText === value.commitMessagePrompt,
42003
+ onClick: () => {
42004
+ if (!generationDisabled) save({ commitMessagePrompt: promptText }).then((accepted) => {
42005
+ if (accepted) setPromptDraft(null);
42006
+ });
42007
+ }
42008
+ }, t(saving ? "git.messagePromptSaving" : "git.messagePromptSave")))));
42009
+ }
42010
+ //#endregion
41336
42011
  //#region src/client/git-history-graph.ts
41337
42012
  /**
41338
42013
  * 版本列表左侧提交图的泳道布局。
@@ -41737,6 +42412,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
41737
42412
  rpc: services.rpc,
41738
42413
  remote: services.remote,
41739
42414
  uiContext: ctx,
42415
+ settings: services.settings,
41740
42416
  t
41741
42417
  })
41742
42418
  }, GitPanel)));
@@ -41800,6 +42476,11 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
41800
42476
  function GitPanel(props) {
41801
42477
  const sessionId = String(props.sessionId);
41802
42478
  const t = props.t;
42479
+ const settingsStore = (0, react.useMemo)(() => ({
42480
+ subscribe: (listener) => props.settings?.subscribe(listener) ?? (() => void 0),
42481
+ read: () => props.settings?.getSnapshot()
42482
+ }), [props.settings]);
42483
+ const generationEnabled = (0, react.useSyncExternalStore)(settingsStore.subscribe, settingsStore.read, settingsStore.read)?.value?.gitManagement?.commitMessageEnabled !== false;
41803
42484
  const tabInfo = props.useTabInfo();
41804
42485
  useGitWorkspaceSnapshot(props.uiContext);
41805
42486
  const projectedWorkspaceId = require_native_workspace_store.readNativeWorkspaceSnapshot(props.uiContext)?.items.find((item) => item.sessionIds.includes(sessionId))?.workspaceId;
@@ -41808,7 +42489,10 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
41808
42489
  const [history, setHistory] = (0, react.useState)([]);
41809
42490
  const [branches, setBranches] = (0, react.useState)(null);
41810
42491
  const [subject, setSubject] = (0, react.useState)("");
41811
- const [busy, setBusy] = (0, react.useState)(false);
42492
+ const [operationBusy, setBusy] = (0, react.useState)(false);
42493
+ const [generating, setGenerating] = (0, react.useState)(false);
42494
+ const draftRequest = (0, react.useRef)(null);
42495
+ const busy = operationBusy || generating;
41812
42496
  const [activeOperation, setActiveOperation] = (0, react.useState)(null);
41813
42497
  const [toast, setToast] = (0, react.useState)(null);
41814
42498
  const [diffView, setDiffView] = (0, react.useState)(null);
@@ -41819,6 +42503,18 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
41819
42503
  const [historyLoadingMore, setHistoryLoadingMore] = (0, react.useState)(false);
41820
42504
  const historyExpanded = (0, react.useRef)(false);
41821
42505
  const gridVisible = status !== null && status.snapshot.enabled !== false;
42506
+ (0, react.useEffect)(() => {
42507
+ setGenerating(false);
42508
+ return () => {
42509
+ draftRequest.current?.abort();
42510
+ draftRequest.current = null;
42511
+ };
42512
+ }, [
42513
+ workspaceId,
42514
+ generationEnabled,
42515
+ sessionId,
42516
+ projectedWorkspaceId
42517
+ ]);
41822
42518
  (0, react.useEffect)(() => {
41823
42519
  if (toast === null) return;
41824
42520
  const timer = globalThis.setTimeout(() => setToast(null), 3200);
@@ -41997,6 +42693,26 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
41997
42693
  }
41998
42694
  run("git/commit", { subject: value }, () => setSubject(""));
41999
42695
  };
42696
+ const generateMessage = async () => {
42697
+ if (!generationEnabled || busy || workspaceId === void 0 || draftRequest.current !== null) return;
42698
+ const abort = new AbortController();
42699
+ draftRequest.current = abort;
42700
+ setGenerating(true);
42701
+ notify("info", t("git.generatingMessage"));
42702
+ try {
42703
+ const draft = await call$1(props.rpc, "git/generate-message", { workspaceId }, abort.signal);
42704
+ if (abort.signal.aborted) return;
42705
+ setSubject(draft.message);
42706
+ setToast(null);
42707
+ } catch (error) {
42708
+ if (!abort.signal.aborted) notify("error", error instanceof Error ? error.message : String(error));
42709
+ } finally {
42710
+ if (draftRequest.current === abort) {
42711
+ draftRequest.current = null;
42712
+ setGenerating(false);
42713
+ }
42714
+ }
42715
+ };
42000
42716
  const copyCommitHash = (commitHash) => {
42001
42717
  copyText(commitHash).then((copied) => notify(copied ? "success" : "error", copied ? t("git.commitHashCopied") : t("git.copyUnsupported")));
42002
42718
  };
@@ -42135,23 +42851,24 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
42135
42851
  }, (0, react.createElement)("section", { style: commitSectionStyle }, (0, react.createElement)("div", { style: sectionHeaderStyle }, (0, react.createElement)("strong", void 0, t("git.commitChanges")), (0, react.createElement)("span", { style: mutedStyle }, staged.length === 0 ? t("git.stagingEmpty") : t("git.stagedCount", { count: staged.length }))), (0, react.createElement)("div", { style: commitEditorRowStyle }, (0, react.createElement)("textarea", {
42136
42852
  value: subject,
42137
42853
  disabled: busy || workspaceId === void 0,
42854
+ maxLength: require_native_workspace_store.MAX_GIT_COMMIT_MESSAGE_CHARS,
42138
42855
  className: gitPanelClass.field,
42139
42856
  onChange: (event) => setSubject(event.currentTarget.value),
42140
- onKeyDown: (event) => {
42141
- if (event.key === "Enter") event.preventDefault();
42142
- },
42143
42857
  placeholder: t("git.commitPlaceholder"),
42144
- rows: 1,
42858
+ rows: Math.min(8, subject.split("\n").length),
42145
42859
  style: commitSubjectStyle
42146
- }), (0, react.createElement)("button", {
42860
+ }), generationEnabled && (0, react.createElement)("button", {
42147
42861
  type: "button",
42148
- disabled: busy || workspaceId === void 0,
42149
- onClick: () => notify("info", t("git.draftUnavailable")),
42862
+ disabled: busy || workspaceId === void 0 || staged.length === 0,
42863
+ onClick: () => {
42864
+ generateMessage();
42865
+ },
42150
42866
  className: `${gitPanelClass.button} ${gitPanelClass.field}`,
42151
42867
  style: draftButtonStyle,
42152
- title: t("git.draftMessage"),
42153
- "aria-label": t("git.draftMessage")
42154
- }, "✦")), (0, react.createElement)("div", { style: commitActionsStyle }, (0, react.createElement)("button", {
42868
+ title: t(generating ? "git.generatingMessage" : "git.draftMessage"),
42869
+ "aria-label": t("git.draftMessage"),
42870
+ "aria-busy": generating
42871
+ }, generating ? "…" : "✦")), (0, react.createElement)("div", { style: commitActionsStyle }, (0, react.createElement)("button", {
42155
42872
  type: "button",
42156
42873
  disabled: busy || workspaceId === void 0,
42157
42874
  onClick: () => void run("git/status", {}, (value) => setStatus(value)),
@@ -43797,7 +44514,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
43797
44514
  width: "100%",
43798
44515
  minHeight: 34,
43799
44516
  boxSizing: "border-box",
43800
- resize: "none",
44517
+ resize: "vertical",
43801
44518
  padding: "7px 10px",
43802
44519
  borderRadius: 8,
43803
44520
  font: "inherit",
@@ -43896,9 +44613,11 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
43896
44613
  context.resources.add(registerGitManagementUi(uiContext, {
43897
44614
  rpc: context.services.rpc,
43898
44615
  remote: context.services.remote,
43899
- locale: context.services.locale
44616
+ locale: context.services.locale,
44617
+ settings: context.services.settings
43900
44618
  }));
43901
- }
44619
+ },
44620
+ settingsPanel: GitManagementSettingsPanel
43902
44621
  };
43903
44622
  //#endregion
43904
44623
  //#region src/client/engine-loader.ts
@@ -43935,6 +44654,8 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
43935
44654
  //#endregion
43936
44655
  //#region src/client/file-management-dom.ts
43937
44656
  const DOCUMENT_PREVIEW_SELECTOR = "[data-document-preview]";
44657
+ const FILE_TREE_ENTRY_SELECTOR = "[data-files-entry][data-files-path]";
44658
+ const PREVIEW_PATH_SELECTOR = "[data-textpreview-path]";
43938
44659
  const loadEditorEngine = createEngineLoader(() => require.async("./client.editor-engine.js"));
43939
44660
  /** 可直接交给文本编辑器的扩展名;未知扩展名仍按只读预览处理,避免误打开二进制文件。 */
43940
44661
  const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -44083,11 +44804,19 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44083
44804
  };
44084
44805
  const onContextMenu = (event) => {
44085
44806
  if (!options.menuEnhancement) return;
44086
- const target = event.target?.closest("[data-files-entry][data-files-path]");
44087
- if (target == null) return;
44807
+ const origin = eventElement(event.target);
44808
+ const treeEntry = origin?.closest(FILE_TREE_ENTRY_SELECTOR);
44809
+ if (treeEntry != null) {
44810
+ event.preventDefault();
44811
+ event.stopPropagation();
44812
+ openMenu(treeEntry, event.clientX, event.clientY);
44813
+ return;
44814
+ }
44815
+ const previewPath = previewPathLabel(origin);
44816
+ if (previewPath == null) return;
44088
44817
  event.preventDefault();
44089
44818
  event.stopPropagation();
44090
- openMenu(target, event.clientX, event.clientY);
44819
+ openPreviewCopyPathMenu(previewPath, event.clientX, event.clientY);
44091
44820
  };
44092
44821
  const onDocumentPointerDown = (event) => {
44093
44822
  if (menu === void 0) return;
@@ -44137,7 +44866,6 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44137
44866
  dispose
44138
44867
  };
44139
44868
  function openMenu(item, x, y) {
44140
- closeMenu();
44141
44869
  const rawPath = item.dataset.filesPath ?? "";
44142
44870
  const kind = item.dataset.filesEntry === "directory" ? "directory" : "file";
44143
44871
  if (rawPath === "") return;
@@ -44153,7 +44881,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44153
44881
  path: base
44154
44882
  };
44155
44883
  const panel = item.closest("[data-files-state=\"tree\"]");
44156
- const items = [
44884
+ showMenu([
44157
44885
  {
44158
44886
  label: t(kind === "directory" ? "fileMenu.expandFolder" : "fileMenu.openFile"),
44159
44887
  action: () => clickEntry(item)
@@ -44217,9 +44945,35 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44217
44945
  label: t("fileMenu.delete"),
44218
44946
  action: () => void deleteEntry(target, panel)
44219
44947
  }
44220
- ];
44948
+ ], x, y, "tree");
44949
+ }
44950
+ function openPreviewCopyPathMenu(pathLabel, x, y) {
44951
+ const parsed = parseFileTarget((pathLabel.closest("[data-textpreview-url], [data-document-preview]")?.getAttribute("data-textpreview-url") ?? "").split(/[?#]/u)[0] ?? "");
44952
+ const displayPath = pathLabel.getAttribute("title")?.trim() || void 0;
44953
+ const workspaceRoot = filesRootForEntry(pathLabel);
44954
+ const paths = resolveFileCopyPaths({
44955
+ ...parsed === void 0 ? {} : { resourcePath: parsed.path },
44956
+ ...displayPath === void 0 ? {} : { displayPath },
44957
+ ...workspaceRoot === void 0 ? {} : { workspaceRoot }
44958
+ });
44959
+ if (paths === void 0) {
44960
+ showNotice(t("fileMenu.unresolvedPath"));
44961
+ return;
44962
+ }
44963
+ showMenu([{
44964
+ label: t("fileMenu.copyRelativePath"),
44965
+ action: () => void copyResolvedFilePath(paths.relative, false, t)
44966
+ }, {
44967
+ label: t("fileMenu.copyAbsolutePath"),
44968
+ action: () => void copyResolvedFilePath(paths.absolute, true, t)
44969
+ }], x, y, "preview");
44970
+ }
44971
+ function showMenu(items, x, y, kind) {
44972
+ closeMenu();
44973
+ if (items.length === 0) return;
44221
44974
  menu = document.createElement("div");
44222
44975
  menu.setAttribute("role", "menu");
44976
+ menu.setAttribute("data-file-management-menu", kind);
44223
44977
  menu.style.cssText = "position:fixed;z-index:2147483647;min-width:190px;padding:5px;background:var(--dsw-alias-bg-layer-3,#242526);border:1px solid var(--dsw-alias-border-l2,#666);border-radius:8px;box-shadow:0 8px 30px #0008;color:var(--dsw-alias-label-primary,#eee);font:13px var(--dsw-font,system-ui,sans-serif)";
44224
44978
  for (const item of items) {
44225
44979
  const button = document.createElement("button");
@@ -44242,7 +44996,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44242
44996
  }
44243
44997
  document.body.append(menu);
44244
44998
  const width = menu.offsetWidth || 190;
44245
- const height = menu.offsetHeight || 360;
44999
+ const height = menu.offsetHeight || (kind === "preview" ? 88 : 360);
44246
45000
  menu.style.left = `${Math.max(8, Math.min(x, window.innerWidth - width - 8))}px`;
44247
45001
  menu.style.top = `${Math.max(8, Math.min(y, window.innerHeight - height - 8))}px`;
44248
45002
  }
@@ -44301,15 +45055,16 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44301
45055
  }
44302
45056
  }
44303
45057
  async function copyPath(item, absolute) {
44304
- const path = item.dataset.filesPath ?? "";
44305
- const root = filesRootForEntry(item);
44306
- const value = absolute ? absolutePath(path, root) : relativePath(path, root);
44307
- try {
44308
- await copyTextToClipboard(value);
44309
- showNotice(t(absolute ? "fileMenu.copiedAbsolutePath" : "fileMenu.copiedRelativePath"));
44310
- } catch {
44311
- showNotice(t("fileMenu.copyPathFailed"));
45058
+ const workspaceRoot = filesRootForEntry(item);
45059
+ const paths = resolveFileCopyPaths({
45060
+ resourcePath: item.dataset.filesPath ?? "",
45061
+ ...workspaceRoot === void 0 ? {} : { workspaceRoot }
45062
+ });
45063
+ if (paths === void 0) {
45064
+ showNotice(t("fileMenu.unresolvedPath"));
45065
+ return;
44312
45066
  }
45067
+ await copyResolvedFilePath(absolute ? paths.absolute : paths.relative, absolute, t);
44313
45068
  }
44314
45069
  async function runMutation(action, payload, panel) {
44315
45070
  try {
@@ -44544,6 +45299,19 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44544
45299
  if (pattern.test(label)) return button;
44545
45300
  }
44546
45301
  }
45302
+ function eventElement(target) {
45303
+ if (target != null && typeof target.closest === "function") return target;
45304
+ const parent = target?.parentElement;
45305
+ return parent != null && typeof parent.closest === "function" ? parent : null;
45306
+ }
45307
+ function previewPathLabel(origin) {
45308
+ if (origin == null || origin.closest("[data-textpreview-body]") != null) return null;
45309
+ const labeled = origin.closest(PREVIEW_PATH_SELECTOR);
45310
+ if (labeled != null) return labeled;
45311
+ const pathLabel = origin.closest("[data-path-label]");
45312
+ if (pathLabel == null) return null;
45313
+ return pathLabel.closest("[data-textpreview-url], [data-document-preview]") == null ? null : pathLabel;
45314
+ }
44547
45315
  function parseFileTarget(url) {
44548
45316
  const match = /^dsh-resource:\/\/file\/session\/([^/]+)\/(.*)$/u.exec(url);
44549
45317
  if (match === null) return void 0;
@@ -44598,6 +45366,29 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
44598
45366
  if (normalizedPath.startsWith(`${normalizedRoot}/`)) return normalizedPath.slice(normalizedRoot.length + 1);
44599
45367
  return path;
44600
45368
  }
45369
+ /** 从资源地址、查看器标题和工作区根目录合成可复制的相对路径与绝对路径。 */
45370
+ function resolveFileCopyPaths(input) {
45371
+ const resourcePath = input.resourcePath?.trim() ?? "";
45372
+ const displayPath = input.displayPath?.trim() ?? "";
45373
+ const resourceAbsolutePath = input.resourceAbsolutePath?.trim() ?? "";
45374
+ const workspaceRoot = input.workspaceRoot?.trim() || void 0;
45375
+ if ((resourcePath || displayPath || resourceAbsolutePath) === "") return void 0;
45376
+ const absolute = resourceAbsolutePath || (isAbsoluteLike(displayPath) ? displayPath : "") || absolutePath(resourcePath || displayPath, workspaceRoot);
45377
+ const relative = relativePath(resourcePath || (isAbsoluteLike(displayPath) ? displayPath : resourcePath) || absolute, workspaceRoot);
45378
+ if (absolute === "" && relative === "") return void 0;
45379
+ return {
45380
+ relative,
45381
+ absolute
45382
+ };
45383
+ }
45384
+ async function copyResolvedFilePath(value, absolute, t) {
45385
+ try {
45386
+ await copyTextToClipboard(value);
45387
+ showNotice(t(absolute ? "fileMenu.copiedAbsolutePath" : "fileMenu.copiedRelativePath"));
45388
+ } catch {
45389
+ showNotice(t("fileMenu.copyPathFailed"));
45390
+ }
45391
+ }
44601
45392
  async function copyTextToClipboard(text) {
44602
45393
  if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) try {
44603
45394
  await navigator.clipboard.writeText(text);
@@ -45555,6 +46346,98 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45555
46346
  };
45556
46347
  const diffContextLineStyle = { display: "block" };
45557
46348
  //#endregion
46349
+ //#region src/client/file-viewer-copy-path-menu.ts
46350
+ const FILE_VIEWER_COPY_PATH_MENU_ID = "codingns4dsh-copy-file-path";
46351
+ /** 标签菜单 extras 在单测或 Slot 未注入 locale 时退回内置中文词典。 */
46352
+ const FALLBACK_LOCALE = {
46353
+ bind: () => require_transport.resolveCodingNsTranslator(void 0),
46354
+ getSnapshot: () => ({ revision: 0 }),
46355
+ subscribe: () => () => void 0,
46356
+ register: () => () => void 0
46357
+ };
46358
+ const tabMenuItemStyle = {
46359
+ display: "block",
46360
+ width: "100%",
46361
+ boxSizing: "border-box",
46362
+ padding: "4px 7px",
46363
+ color: "var(--dsw-alias-label-primary)",
46364
+ fontSize: "calc(var(--dsh-content-font-size-secondary, 13px) - 1px)",
46365
+ textAlign: "left",
46366
+ background: "transparent",
46367
+ border: "none",
46368
+ borderRadius: "var(--dsw-radius-md)",
46369
+ cursor: "pointer"
46370
+ };
46371
+ /** 在文件查看器标签的原生右键菜单末尾加入复制相对/绝对路径。 */
46372
+ function registerFileViewerCopyPathMenu(slots, locale) {
46373
+ if (slots === void 0 || typeof slots.inject !== "function" || typeof slots.register !== "function") return () => void 0;
46374
+ try {
46375
+ return slots.inject("sidebar.right.tab.menu.item", () => slots.register({
46376
+ name: "sidebar.right.tab.menu.item",
46377
+ id: FILE_VIEWER_COPY_PATH_MENU_ID,
46378
+ order: 80
46379
+ }, function FileTabCopyPathMenu(props) {
46380
+ const resolvedLocale = props.locale ?? locale;
46381
+ return FileTabCopyPathMenuItems({
46382
+ ...props,
46383
+ ...resolvedLocale === void 0 ? {} : { locale: resolvedLocale }
46384
+ });
46385
+ }));
46386
+ } catch {
46387
+ return () => void 0;
46388
+ }
46389
+ }
46390
+ function FileTabCopyPathMenuItems(props) {
46391
+ const t = require_transport.useCodingNsTranslator(props.locale ?? FALLBACK_LOCALE);
46392
+ const paths = fileCopyPathsForTab(props);
46393
+ if (paths === void 0) return null;
46394
+ return (0, react.createElement)(react.Fragment, null, copyPathMenuItem(t, "fileMenu.copyRelativePath", "relative", () => {
46395
+ props.dismiss();
46396
+ copyResolvedFilePath(paths.relative, false, t);
46397
+ }), copyPathMenuItem(t, "fileMenu.copyAbsolutePath", "absolute", () => {
46398
+ props.dismiss();
46399
+ copyResolvedFilePath(paths.absolute, true, t);
46400
+ }));
46401
+ }
46402
+ function fileCopyPathsForTab(props) {
46403
+ const address = (props.tab.contentId ?? "").split(/[?#]/u)[0] ?? "";
46404
+ const parsed = parseFileTarget(address);
46405
+ if (parsed === void 0) return void 0;
46406
+ const workspaceRoot = workspaceRootForSession(props.sessionId);
46407
+ const resourceAbsolutePath = props.useResource?.(address)?.value?.absolutePath;
46408
+ return resolveFileCopyPaths({
46409
+ resourcePath: parsed.path,
46410
+ ...workspaceRoot === void 0 ? {} : { workspaceRoot },
46411
+ ...resourceAbsolutePath === void 0 ? {} : { resourceAbsolutePath }
46412
+ });
46413
+ }
46414
+ function copyPathMenuItem(t, key, kind, onSelect) {
46415
+ return (0, react.createElement)("button", {
46416
+ type: "button",
46417
+ role: "menuitem",
46418
+ "data-file-copy-path": kind,
46419
+ style: tabMenuItemStyle,
46420
+ onMouseEnter: (event) => {
46421
+ event.currentTarget.style.background = "var(--dsw-alias-interactive-bg-hover, rgba(127,127,127,.12))";
46422
+ },
46423
+ onMouseLeave: (event) => {
46424
+ event.currentTarget.style.background = "transparent";
46425
+ },
46426
+ onClick: onSelect
46427
+ }, t(key));
46428
+ }
46429
+ function workspaceRootForSession(sessionId) {
46430
+ if (typeof document === "undefined") return void 0;
46431
+ if (sessionId !== void 0 && sessionId !== "") {
46432
+ const scoped = document.querySelector(`[data-sidebar-right-session="${cssAttribute(sessionId)}"] [data-files-root]`)?.getAttribute("data-files-root")?.trim();
46433
+ if (scoped) return scoped;
46434
+ }
46435
+ return document.querySelector("[data-files-root]")?.getAttribute("data-files-root")?.trim() || void 0;
46436
+ }
46437
+ function cssAttribute(value) {
46438
+ return value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
46439
+ }
46440
+ //#endregion
45558
46441
  //#region src/client/html-workspace-files.ts
45559
46442
  const REQUEST = "codingns.html-files.request.v1";
45560
46443
  const RESPONSE = "codingns.html-files.response.v1";
@@ -45736,6 +46619,8 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45736
46619
  const dom = startFileManagementDom(context.services.rpc, readOptions());
45737
46620
  context.resources.add(startHtmlWorkspaceFiles(context.services.rpc, context.services.locale));
45738
46621
  let disposeSessionView;
46622
+ let disposeCopyPathMenu;
46623
+ const slots = context.services.uiContext?.slots ?? context.services.slots;
45739
46624
  const syncSessionView = () => {
45740
46625
  const value = {
45741
46626
  ...require_native_workspace_store.DEFAULT_FILE_MANAGEMENT_SETTINGS,
@@ -45747,14 +46632,28 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45747
46632
  disposeSessionView = void 0;
45748
46633
  }
45749
46634
  };
46635
+ const syncCopyPathMenu = () => {
46636
+ const value = {
46637
+ ...require_native_workspace_store.DEFAULT_FILE_MANAGEMENT_SETTINGS,
46638
+ ...context.services.settings.getSnapshot().value?.fileManagement
46639
+ };
46640
+ if (value.menuEnhancement && disposeCopyPathMenu === void 0) disposeCopyPathMenu = registerFileViewerCopyPathMenu(slots, context.services.locale);
46641
+ else if (!value.menuEnhancement && disposeCopyPathMenu !== void 0) {
46642
+ disposeCopyPathMenu();
46643
+ disposeCopyPathMenu = void 0;
46644
+ }
46645
+ };
45750
46646
  syncSessionView();
46647
+ syncCopyPathMenu();
45751
46648
  const unsubscribe = context.services.settings.subscribe(() => {
45752
46649
  dom.setOptions(readOptions());
45753
46650
  syncSessionView();
46651
+ syncCopyPathMenu();
45754
46652
  });
45755
46653
  context.resources.add(unsubscribe);
45756
46654
  context.resources.add(dom.dispose);
45757
46655
  context.resources.add(() => disposeSessionView?.());
46656
+ context.resources.add(() => disposeCopyPathMenu?.());
45758
46657
  },
45759
46658
  settingsPanel: FileManagementPanel
45760
46659
  };
@@ -45834,7 +46733,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45834
46733
  saved.push(app);
45835
46734
  continue;
45836
46735
  }
45837
- const { id, title, hostId, workspaceId, entryPath, documentRoot, kind, fileAccess, spaFallback, mounts } = app;
46736
+ const { id, title, hostId, workspaceId, entryPath, documentRoot, kind, fileAccess, spaFallback, networkAllow, mounts } = app;
45838
46737
  saved.push(await this.call("upsert", {
45839
46738
  expectedRevision: app.revision,
45840
46739
  app: {
@@ -45847,6 +46746,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45847
46746
  kind,
45848
46747
  ...fileAccess ? { fileAccess } : {},
45849
46748
  spaFallback,
46749
+ ...networkAllow?.length ? { networkAllow } : {},
45850
46750
  mounts,
45851
46751
  order
45852
46752
  }
@@ -45878,6 +46778,176 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45878
46778
  }
45879
46779
  };
45880
46780
  //#endregion
46781
+ //#region src/shared/quick-app-network-allow.ts
46782
+ const RANGES = [
46783
+ ["0.0.0.0", 8],
46784
+ ["10.0.0.0", 8],
46785
+ ["100.64.0.0", 10],
46786
+ ["127.0.0.0", 8],
46787
+ ["169.254.0.0", 16],
46788
+ ["172.16.0.0", 12],
46789
+ ["192.0.0.0", 24],
46790
+ ["192.0.2.0", 24],
46791
+ ["192.88.99.0", 24],
46792
+ ["192.168.0.0", 16],
46793
+ ["198.18.0.0", 15],
46794
+ ["198.51.100.0", 24],
46795
+ ["203.0.113.0", 24],
46796
+ ["224.0.0.0", 4],
46797
+ ["240.0.0.0", 4],
46798
+ ["255.255.255.255", 32],
46799
+ ["::", 128],
46800
+ ["::1", 128],
46801
+ ["fc00::", 7],
46802
+ ["fe80::", 10],
46803
+ ["ff00::", 8],
46804
+ ["2001:db8::", 32]
46805
+ ].map(([text, prefix]) => {
46806
+ const ip = parseIp(text);
46807
+ if (!ip) throw new Error(`Invalid egress range ${text}.`);
46808
+ return {
46809
+ family: ip.family,
46810
+ bytes: ip.bytes,
46811
+ prefix
46812
+ };
46813
+ });
46814
+ function parseQuickAppNetworkAllow(value) {
46815
+ if (value === void 0) return [];
46816
+ if (!Array.isArray(value) || value.length > 16) throw invalid();
46817
+ const allow = [];
46818
+ const seen = /* @__PURE__ */ new Set();
46819
+ for (const item of value) {
46820
+ if (typeof item !== "string") throw invalid();
46821
+ const text = item.trim().toLowerCase();
46822
+ if (!text) continue;
46823
+ const canonical = canonicalEntry(text);
46824
+ if (!canonical) throw invalid();
46825
+ if (seen.has(canonical)) continue;
46826
+ seen.add(canonical);
46827
+ allow.push(canonical);
46828
+ }
46829
+ return allow;
46830
+ }
46831
+ function canonicalEntry(text) {
46832
+ if (text.length > 253) return null;
46833
+ const slash = text.lastIndexOf("/");
46834
+ if (slash > 0) {
46835
+ const prefix = Number(text.slice(slash + 1));
46836
+ const ip = canonicalIp(text.slice(0, slash));
46837
+ const max = ip?.family === 4 ? 32 : 128;
46838
+ if (!ip || !/^\d{1,3}$/u.test(text.slice(slash + 1)) || prefix < 1 || prefix > max || !blockedRange(ip, prefix)) return null;
46839
+ const network = mask(ip.bytes, prefix);
46840
+ const formatted = formatIp({
46841
+ family: ip.family,
46842
+ bytes: network
46843
+ });
46844
+ return prefix === max ? formatted : `${formatted}/${prefix}`;
46845
+ }
46846
+ const ip = canonicalIp(text);
46847
+ if (ip) return blockedRange(ip, ip.family === 4 ? 32 : 128) ? formatIp(ip) : null;
46848
+ const host = text.endsWith(".") ? text.slice(0, -1) : text;
46849
+ if (!host || host.endsWith(".") || /^\d+$/u.test(host) || parseIp(host)) return null;
46850
+ return /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(host) ? host : null;
46851
+ }
46852
+ function blockedRange(ip, prefix) {
46853
+ return RANGES.some((range) => range.family === ip.family && range.prefix <= prefix && samePrefix(range.bytes, ip.bytes, range.prefix));
46854
+ }
46855
+ function canonicalIp(text) {
46856
+ const parsed = parseIp(text);
46857
+ if (!parsed) return null;
46858
+ if (parsed.family === 6 && parsed.bytes.subarray(0, 10).every((byte) => byte === 0) && parsed.bytes[10] === 255 && parsed.bytes[11] === 255) return {
46859
+ family: 4,
46860
+ bytes: parsed.bytes.subarray(12)
46861
+ };
46862
+ return parsed;
46863
+ }
46864
+ function parseIp(text) {
46865
+ if (text.includes("%") || text.includes("/")) return null;
46866
+ if (/^(?:0|[1-9]\d{0,2})(?:\.(?:0|[1-9]\d{0,2})){3}$/u.test(text)) {
46867
+ const bytes = text.split(".").map((part) => Number(part));
46868
+ if (bytes.every((part) => part <= 255)) return {
46869
+ family: 4,
46870
+ bytes: Uint8Array.from(bytes)
46871
+ };
46872
+ return null;
46873
+ }
46874
+ const halves = text.split("::");
46875
+ if (halves.length > 2) return null;
46876
+ const side = (value) => {
46877
+ if (value === "") return [];
46878
+ const parts = value.split(":");
46879
+ const groups = [];
46880
+ for (let index = 0; index < parts.length; index += 1) {
46881
+ const part = parts[index] ?? "";
46882
+ if (index === parts.length - 1 && part.includes(".")) {
46883
+ const tail = parseIp(part);
46884
+ if (tail?.family !== 4) return null;
46885
+ groups.push(tail.bytes[0] << 8 | tail.bytes[1], tail.bytes[2] << 8 | tail.bytes[3]);
46886
+ } else if (!/^[0-9a-f]{1,4}$/u.test(part)) return null;
46887
+ else groups.push(Number.parseInt(part, 16));
46888
+ }
46889
+ return groups;
46890
+ };
46891
+ const left = side(halves[0] ?? "");
46892
+ const right = halves.length === 2 ? side(halves[1] ?? "") : [];
46893
+ if (!left || !right || halves.length === 1 && left.length !== 8 || halves.length === 2 && left.length + right.length >= 8) return null;
46894
+ const groups = halves.length === 1 ? left : [
46895
+ ...left,
46896
+ ...Array(8 - left.length - right.length).fill(0),
46897
+ ...right
46898
+ ];
46899
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
46900
+ groups.forEach((group, index) => {
46901
+ bytes[index * 2] = group >> 8;
46902
+ bytes[index * 2 + 1] = group & 255;
46903
+ });
46904
+ return {
46905
+ family: 6,
46906
+ bytes
46907
+ };
46908
+ }
46909
+ function formatIp(ip) {
46910
+ if (ip.family === 4) return [...ip.bytes].join(".");
46911
+ const groups = Array.from({ length: 8 }, (_, index) => ip.bytes[index * 2] << 8 | ip.bytes[index * 2 + 1]);
46912
+ let start = -1;
46913
+ let length = 0;
46914
+ for (let index = 0; index < groups.length;) {
46915
+ if (groups[index] !== 0) {
46916
+ index += 1;
46917
+ continue;
46918
+ }
46919
+ let end = index;
46920
+ while (end < groups.length && groups[end] === 0) end += 1;
46921
+ if (end - index > length) {
46922
+ start = index;
46923
+ length = end - index;
46924
+ }
46925
+ index = end;
46926
+ }
46927
+ const hex = groups.map((group) => group.toString(16));
46928
+ if (length < 2) return hex.join(":");
46929
+ return `${hex.slice(0, start).join(":")}::${hex.slice(start + length).join(":")}`;
46930
+ }
46931
+ function mask(bytes, prefix) {
46932
+ const out = bytes.slice();
46933
+ const whole = Math.floor(prefix / 8);
46934
+ const bits = prefix % 8;
46935
+ if (bits) out[whole] = (out[whole] ?? 0) & 255 << 8 - bits;
46936
+ for (let index = whole + (bits ? 1 : 0); index < out.length; index += 1) out[index] = 0;
46937
+ return out;
46938
+ }
46939
+ function samePrefix(left, right, prefix) {
46940
+ const whole = Math.floor(prefix / 8);
46941
+ for (let index = 0; index < whole; index += 1) if (left[index] !== right[index]) return false;
46942
+ const bits = prefix % 8;
46943
+ if (!bits) return true;
46944
+ const select = 255 << 8 - bits & 255;
46945
+ return ((left[whole] ?? 0) & select) === ((right[whole] ?? 0) & select);
46946
+ }
46947
+ function invalid() {
46948
+ return /* @__PURE__ */ new Error("Invalid local network allow list.");
46949
+ }
46950
+ //#endregion
45881
46951
  //#region src/client/quick-apps/presentation.ts
45882
46952
  function newQuickAppDraft(order) {
45883
46953
  return {
@@ -45890,6 +46960,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45890
46960
  kind: "html",
45891
46961
  fileAccess: "workspace",
45892
46962
  spaFallback: false,
46963
+ networkAllow: [],
45893
46964
  mounts: [],
45894
46965
  order,
45895
46966
  expectedRevision: 0
@@ -45909,7 +46980,19 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45909
46980
  };
45910
46981
  }
45911
46982
  function draftChanged(draft, app) {
45912
- return Object.keys(newQuickAppDraft(0)).some((key) => key !== "expectedRevision" && JSON.stringify(draft[key]) !== JSON.stringify(app[key]));
46983
+ return Object.keys(newQuickAppDraft(0)).some((key) => {
46984
+ if (key === "expectedRevision") return false;
46985
+ if (key === "networkAllow") return !sameNetworkAllow(draft.networkAllow, app.networkAllow);
46986
+ return JSON.stringify(draft[key]) !== JSON.stringify(app[key]);
46987
+ });
46988
+ }
46989
+ function sameNetworkAllow(draft, saved) {
46990
+ const lines = (draft ?? []).map((item) => item.trim()).filter(Boolean);
46991
+ try {
46992
+ return JSON.stringify(parseQuickAppNetworkAllow(lines)) === JSON.stringify(parseQuickAppNetworkAllow(saved ?? []));
46993
+ } catch {
46994
+ return false;
46995
+ }
45913
46996
  }
45914
46997
  /** Match the parent workspace shortcut rail's stable, name-based icon treatment. */
45915
46998
  function shortcutIcon(app) {
@@ -45990,7 +47073,8 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
45990
47073
  .codingns-quick-app-rail button:disabled{opacity:.5;cursor:not-allowed}
45991
47074
  .codingns-quick-app-rail button:focus-visible{outline:2px solid ${require_theme.dshThemeColor.accent};outline-offset:-2px}
45992
47075
  .codingns-quick-app-rail .qa-grid{position:relative;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:4px;padding-top:4px;max-height:min(35dvh,240px);overflow:auto;overscroll-behavior:contain}
45993
- .codingns-quick-app-rail .qa-shortcut{position:relative;min-width:0}
47076
+ /* Clip the edit-mode tilt. Its rotating border box would otherwise become scrollable overflow and toggle the grid scrollbar, which shifts the rows below. */
47077
+ .codingns-quick-app-rail .qa-shortcut{position:relative;min-width:0;overflow:clip}
45994
47078
  .codingns-quick-app-rail .qa-tile{display:flex;flex-direction:column;align-items:center;gap:3px;width:100%;min-width:0;min-height:54px;padding:2px;border:0;border-radius:8px;background:transparent;color:inherit;font:inherit;cursor:pointer}
45995
47079
  .codingns-quick-app-rail .qa-tile[data-editing=true]{outline:1px dashed ${require_theme.dshThemeColor.border};outline-offset:-1px;cursor:grab;touch-action:none;user-select:none;-webkit-touch-callout:none}
45996
47080
  .codingns-quick-app-rail .qa-tile[data-dragging=true]{cursor:grabbing;background:${require_theme.dshThemeColor.hoverBackground};outline:2px solid ${require_theme.dshThemeColor.accent};opacity:.7}
@@ -46034,6 +47118,9 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
46034
47118
  /* DSH Input paints its wrapper; the inner input must remain undecorated. */
46035
47119
  .codingns-quick-app-dialog :is(.qa-input,.qa-select,.qa-file-input){box-sizing:border-box;width:100%;min-width:0;max-width:100%;height:40px;border:0;border-radius:8px;background:${require_theme.dshThemeColor.surfaceSubtle};color:${require_theme.dshThemeColor.labelPrimary};font:inherit;font-size:${require_theme.uiFontSize(13)};font-weight:400}
46036
47120
  .codingns-quick-app-dialog :is(.qa-input,.qa-select){padding:0 11px}
47121
+ .codingns-quick-app-dialog .qa-allow{box-sizing:border-box;width:100%;min-width:0;min-height:88px;padding:8px 11px;border:0;border-radius:8px;background:${require_theme.dshThemeColor.surfaceSubtle};color:${require_theme.dshThemeColor.labelPrimary};font:inherit;font-size:${require_theme.uiFontSize(13)};font-weight:400;resize:vertical}
47122
+ .codingns-quick-app-dialog .qa-allow:focus{outline:2px solid ${require_theme.dshThemeColor.accent};outline-offset:-2px}
47123
+ .codingns-quick-app-dialog .qa-allow:disabled{opacity:.5}
46037
47124
  .codingns-quick-app-dialog .qa-input input{width:100%;min-width:0;padding:0;border:0;border-radius:0;outline:none;background:transparent;color:inherit;font:inherit;box-shadow:none}
46038
47125
  .codingns-quick-app-dialog :is(.qa-input,.qa-file-input):focus-within{outline:2px solid ${require_theme.dshThemeColor.accent};outline-offset:-2px}
46039
47126
  .codingns-quick-app-dialog :is(.qa-input,.qa-file-input):has(input:disabled){opacity:.5}
@@ -46080,8 +47167,14 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
46080
47167
  .codingns-quick-app-dialog .qa-view-surface{display:flex;flex:1;flex-direction:column;min-width:0;min-height:0;color:${require_theme.dshThemeColor.labelPrimary};background:${require_theme.dshThemeColor.pageBackground}}
46081
47168
  .codingns-quick-app-dialog :is(.qa-view-titlebar,.qa-view-toolbar){display:flex;flex:none;align-items:center;gap:4px;box-sizing:border-box;height:38px;padding:0 6px 0 16px;border-bottom:.5px solid ${require_theme.dshThemeColor.menuBorder}}
46082
47169
  .codingns-quick-app-dialog .qa-view-titlebar{gap:8px}
47170
+ .codingns-quick-app-dialog .qa-view-title{display:flex;flex:1;align-items:center;gap:8px;min-width:0}
46083
47171
  .codingns-quick-app-dialog .qa-view-titlebar h2{flex:1;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:${require_theme.uiFontSize(13)};font-weight:500}
46084
- .codingns-quick-app-dialog .qa-view-titlebar>svg{flex:none}
47172
+ .codingns-quick-app-dialog .qa-view-title>svg{flex:none}
47173
+ /* Fullscreen title sits in the window chrome. Center the name clear of the macOS traffic lights and the trailing controls. */
47174
+ .codingns-quick-app-dialog.qa-viewer.qa-maximized .qa-view-titlebar{position:relative;justify-content:flex-end}
47175
+ .codingns-quick-app-dialog.qa-viewer.qa-maximized .qa-view-title{position:absolute;left:88px;right:88px;top:0;height:100%;flex:none;justify-content:center;pointer-events:none}
47176
+ .codingns-quick-app-dialog.qa-viewer.qa-maximized .qa-view-title>svg{display:none}
47177
+ .codingns-quick-app-dialog.qa-viewer.qa-maximized .qa-view-title h2{flex:0 1 auto;text-align:center}
46085
47178
  .codingns-quick-app-dialog .qa-view-tool{display:inline-flex;flex:none;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:0;border-radius:var(--dsw-radius-sm,6px);background:transparent;color:${require_theme.dshThemeColor.labelSecondary};cursor:pointer}
46086
47179
  .codingns-quick-app-dialog .qa-view-tool svg{width:15px;height:15px}
46087
47180
  .codingns-quick-app-dialog .qa-view-tool:hover:not(:disabled){color:${require_theme.dshThemeColor.labelPrimary};background:${require_theme.dshThemeColor.hoverBackground}}
@@ -57647,14 +58740,14 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
57647
58740
  }, (0, react.createElement)("section", {
57648
58741
  className: `qa-view-surface qa-view-${view.kind}`,
57649
58742
  "aria-busy": disabled
57650
- }, (0, react.createElement)("header", { className: "qa-view-titlebar" }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
58743
+ }, (0, react.createElement)("header", { className: "qa-view-titlebar" }, (0, react.createElement)("div", { className: "qa-view-title" }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
57651
58744
  kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(path),
57652
58745
  size: 16
57653
58746
  }), (0, react.createElement)("h2", null, app.title), dirty ? (0, react.createElement)("span", {
57654
58747
  className: "qa-document-dirty",
57655
58748
  title: t("quickApps.unsaved"),
57656
58749
  "aria-label": t("quickApps.unsaved")
57657
- }, "●") : null, tool(t(maximized ? "quickApps.restore" : "quickApps.maximize"), require_primitives_adapter.resolveViewerIcon(maximized ? "restore" : "fullscreen"), () => setMaximized(!maximized), { pressed: maximized }), tool(t("quickApps.back"), require_primitives_adapter.resolveAssistantControlIcon("close"), () => guard(onClose), { disabled })), (0, react.createElement)("div", {
58750
+ }, "●") : null), tool(t(maximized ? "quickApps.restore" : "quickApps.maximize"), require_primitives_adapter.resolveViewerIcon(maximized ? "restore" : "fullscreen"), () => setMaximized(!maximized), { pressed: maximized }), tool(t("quickApps.back"), require_primitives_adapter.resolveAssistantControlIcon("close"), () => guard(onClose), { disabled })), (0, react.createElement)("div", {
57658
58751
  className: "qa-view-toolbar",
57659
58752
  role: "group",
57660
58753
  "aria-label": t("quickApps.viewerTools")
@@ -57954,6 +59047,22 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
57954
59047
  };
57955
59048
  }
57956
59049
  //#endregion
59050
+ //#region src/client/quick-apps/rail-preference.ts
59051
+ const QUICK_APPS_RAIL_COLLAPSED_KEY = "codingns4dsh.quickApps.railCollapsed";
59052
+ /** Edit mode is a session action; only the collapsed rail is restored after reload. */
59053
+ function readQuickAppsRailCollapsed() {
59054
+ try {
59055
+ return globalThis.localStorage?.getItem(QUICK_APPS_RAIL_COLLAPSED_KEY) === "1";
59056
+ } catch {
59057
+ return false;
59058
+ }
59059
+ }
59060
+ function writeQuickAppsRailCollapsed(collapsed) {
59061
+ try {
59062
+ globalThis.localStorage?.setItem(QUICK_APPS_RAIL_COLLAPSED_KEY, collapsed ? "1" : "0");
59063
+ } catch {}
59064
+ }
59065
+ //#endregion
57957
59066
  //#region src/client/settings-anchor.ts
57958
59067
  /**
57959
59068
  * 设置区锚点解析。
@@ -58085,9 +59194,17 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
58085
59194
  const formId = (0, react.useId)();
58086
59195
  const client = (0, react.useMemo)(() => new QuickAppsClient(services.rpc), [services.rpc]);
58087
59196
  const [screen, setScreen] = (0, react.useState)(null);
58088
- const [mode, setMode] = (0, react.useState)("normal");
59197
+ const [mode, setMode] = (0, react.useState)(() => readQuickAppsRailCollapsed() ? "collapsed" : "normal");
58089
59198
  const editing = mode === "edit";
58090
59199
  const collapsed = mode === "collapsed";
59200
+ const expandRail = () => {
59201
+ writeQuickAppsRailCollapsed(false);
59202
+ setMode("normal");
59203
+ };
59204
+ const collapseRail = () => {
59205
+ writeQuickAppsRailCollapsed(true);
59206
+ setMode("collapsed");
59207
+ };
58091
59208
  const [pickingFile, setPickingFile] = (0, react.useState)(false);
58092
59209
  const [apps, setApps] = (0, react.useState)([]);
58093
59210
  const [notice, setNotice] = (0, react.useState)(null);
@@ -58229,16 +59346,25 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
58229
59346
  const invalid = {};
58230
59347
  if (!workspaces.some((workspace) => workspace.workspaceId === draft.workspaceId && (workspace.hostId ?? "local") === draft.hostId)) invalid.workspaceId = t("quickApps.chooseWorkspace");
58231
59348
  if (!draft.entryPath.trim()) invalid.entryPath = t("quickApps.entryRequired");
59349
+ const lines = (draft.networkAllow ?? []).map((line) => line.trim()).filter(Boolean);
59350
+ let networkAllow = [];
59351
+ try {
59352
+ networkAllow = parseQuickAppNetworkAllow(lines);
59353
+ } catch {
59354
+ invalid.networkAllow = t("quickApps.networkAllowInvalid");
59355
+ }
58232
59356
  if (Object.keys(invalid).length) {
58233
59357
  setErrors(invalid);
58234
59358
  return;
58235
59359
  }
58236
59360
  perform(async (current) => {
59361
+ const { networkAllow: _draftAllow, ...fields } = draft;
58237
59362
  const saved = await client.call("upsert", {
58238
59363
  app: {
58239
- ...draft,
59364
+ ...fields,
58240
59365
  fileAccess: draft.kind === "html" ? "workspace" : void 0,
58241
- title: draft.title.trim() || entryTitle(draft.entryPath)
59366
+ title: draft.title.trim() || entryTitle(draft.entryPath),
59367
+ ...networkAllow.length ? { networkAllow } : {}
58242
59368
  },
58243
59369
  expectedRevision: draft.expectedRevision
58244
59370
  });
@@ -58339,7 +59465,23 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
58339
59465
  value: draft.kind,
58340
59466
  disabled: busy,
58341
59467
  onChange: (event) => updateDraft({ kind: event.target.value })
58342
- }, (0, react.createElement)("option", { value: "html" }, t("quickApps.html")), (0, react.createElement)("option", { value: "text" }, t("quickApps.text")))), draft.kind === "html" && selected ? (0, react.createElement)("p", { className: "qa-help" }, t("quickApps.workspaceAccessHelp", { workspace: selected.title })) : null, draft.id ? (0, react.createElement)("fieldset", {
59468
+ }, (0, react.createElement)("option", { value: "html" }, t("quickApps.html")), (0, react.createElement)("option", { value: "text" }, t("quickApps.text")))), (0, react.createElement)(QuickAppField, {
59469
+ id: `${formId}-network-allow`,
59470
+ label: t("quickApps.networkAllow"),
59471
+ error: errors.networkAllow,
59472
+ help: t("quickApps.networkAllowHelp")
59473
+ }, (0, react.createElement)("textarea", {
59474
+ id: `${formId}-network-allow`,
59475
+ className: "qa-allow",
59476
+ rows: 4,
59477
+ value: (draft.networkAllow ?? []).join("\n"),
59478
+ disabled: busy,
59479
+ spellCheck: false,
59480
+ placeholder: t("quickApps.networkAllowPlaceholder"),
59481
+ "aria-invalid": Boolean(errors.networkAllow),
59482
+ "aria-describedby": `${formId}-network-allow-help`,
59483
+ onChange: (event) => updateDraft({ networkAllow: event.target.value.split("\n") })
59484
+ })), draft.kind === "html" && selected ? (0, react.createElement)("p", { className: "qa-help" }, t("quickApps.workspaceAccessHelp", { workspace: selected.title })) : null, draft.id ? (0, react.createElement)("fieldset", {
58343
59485
  className: "qa-management",
58344
59486
  disabled: busy || changed,
58345
59487
  "aria-label": t("quickApps.accessAndRemoval")
@@ -58408,10 +59550,10 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
58408
59550
  }, apps.length) : null, (0, react.createElement)("div", { className: "qa-controls" }, !collapsed ? editing ? control(t("quickApps.add"), "add", add) : control(t("quickApps.manage"), "edit", () => {
58409
59551
  setMode("edit");
58410
59552
  setNotice(null);
58411
- }) : null, collapsed ? control(t("quickApps.expandBar"), "expand", () => setMode("normal")) : editing ? control(t("quickApps.done"), "done", () => {
59553
+ }) : null, collapsed ? control(t("quickApps.expandBar"), "expand", expandRail) : editing ? control(t("quickApps.done"), "done", () => {
58412
59554
  setMode("normal");
58413
59555
  setNotice(null);
58414
- }) : control(t("quickApps.collapseBar"), "collapse", () => setMode("collapsed")))), !collapsed ? (0, react.createElement)("div", { className: "qa-rail-content" }, !screen && notice ? (0, react.createElement)("p", {
59556
+ }) : control(t("quickApps.collapseBar"), "collapse", collapseRail))), !collapsed ? (0, react.createElement)("div", { className: "qa-rail-content" }, !screen && notice ? (0, react.createElement)("p", {
58415
59557
  className: "qa-rail-notice",
58416
59558
  role: notice.tone === "error" ? "alert" : "status",
58417
59559
  title: notice.text
@@ -62045,6 +63187,34 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${require_theme.dsh
62045
63187
  return require_primitives_adapter.parseVirtualWorkspaceId(workspaceId)?.targetHostId ?? void 0;
62046
63188
  }
62047
63189
  //#endregion
63190
+ //#region src/dsh-capabilities/client/peer-host-attachment-adapter.ts
63191
+ /** Native file paths describe the client machine; remote sessions must upload bytes. */
63192
+ function installPeerHostAttachmentIntake(context, folderError) {
63193
+ const slots = context?.get?.("slots");
63194
+ if (slots === void 0 || ![
63195
+ "inject",
63196
+ "register",
63197
+ "entries",
63198
+ "subscribe"
63199
+ ].every((key) => typeof slots[key] === "function")) return () => void 0;
63200
+ return installComposerPresentation(context, slots, (Native) => function PeerHostComposer(props) {
63201
+ if (typeof props.sessionId !== "string" || require_primitives_adapter.parseVirtualSessionId(props.sessionId) === null || typeof props.addFiles !== "function") return (0, react.createElement)(Native, props);
63202
+ return (0, react.createElement)(Native, {
63203
+ ...props,
63204
+ addFiles: (files, directories) => {
63205
+ if (files.some((file) => directories?.has(file))) return folderError;
63206
+ return props.addFiles(files.map((file) => new File([file], file.name, {
63207
+ type: file.type,
63208
+ lastModified: file.lastModified
63209
+ })));
63210
+ }
63211
+ });
63212
+ }, react.createElement, {
63213
+ useMemo: react.useMemo,
63214
+ useSyncExternalStore: react.useSyncExternalStore
63215
+ });
63216
+ }
63217
+ //#endregion
62048
63218
  //#region src/client/features/peer-host.ts
62049
63219
  /** 聚合刷新周期;远端资源只影响自身节点,刷新失败不改变本机界面。 */
62050
63220
  const PEER_HOST_AGGREGATE_REFRESH_MS = 3e4;
@@ -62213,6 +63383,7 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${require_theme.dsh
62213
63383
  const fetchImpl = typeof originalGlobalFetch === "function" ? originalGlobalFetch.bind(globalThis) : void 0;
62214
63384
  const scopes = /* @__PURE__ */ new Map();
62215
63385
  const remoteHostScopes = /* @__PURE__ */ new Map();
63386
+ const restoreAttachmentIntake = installPeerHostAttachmentIntake(uiContext, t("peerHost.attachmentFolderUnsupported"));
62216
63387
  let activeModelCatalogScopeKey;
62217
63388
  const modelCatalogScopeKey = (scope) => {
62218
63389
  if (scope?.targetHostId === null || scope?.targetHostId === void 0) return void 0;
@@ -62815,6 +63986,7 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${require_theme.dsh
62815
63986
  mergeEvents: (local, signal) => events.open(local, signal),
62816
63987
  dispose() {
62817
63988
  events.dispose();
63989
+ restoreAttachmentIntake();
62818
63990
  restoreAnchorClick();
62819
63991
  restoreGlobalFetch();
62820
63992
  if (aggregateRefreshTimer !== void 0) clearTimeout(aggregateRefreshTimer);
@@ -68655,386 +69827,6 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${require_theme.dsh
68655
69827
  context.resources.add(dispose);
68656
69828
  }
68657
69829
  };
68658
- //#endregion
68659
- //#region src/client/session-translation-model-pool.ts
68660
- /** The persisted pool owns priority; modal choices and drag previews remain local until confirmed. */
68661
- function SessionTranslationModelPool({ value, catalog, disabled, pending, t, onChange }) {
68662
- const pool = value.translationModels ?? (value.translationModel === void 0 ? [] : [value.translationModel]);
68663
- const available = new Map((catalog?.models ?? []).filter((model) => !require_session_translation.isSessionTranslationAdapter(model.provider)).map((model) => [modelKey(model), model]));
68664
- const pooled = new Set(pool.map(modelKey));
68665
- const [selection, setSelection] = (0, react.useState)(null);
68666
- const [search, setSearch] = (0, react.useState)("");
68667
- const [saveFailed, setSaveFailed] = (0, react.useState)(false);
68668
- const [resetOpen, setResetOpen] = (0, react.useState)(false);
68669
- const [resetFailed, setResetFailed] = (0, react.useState)(false);
68670
- const [preview, setPreview] = (0, react.useState)(null);
68671
- const [announcement, setAnnouncement] = (0, react.useState)("");
68672
- const drag = (0, react.useRef)(null);
68673
- const list = (0, react.useRef)(null);
68674
- const poolIdentity = JSON.stringify(pool);
68675
- const pickerOpen = selection !== null;
68676
- const locked = disabled || pickerOpen || resetOpen;
68677
- const cancelDrag = () => {
68678
- drag.current = null;
68679
- setPreview(null);
68680
- };
68681
- (0, react.useEffect)(() => {
68682
- cancelDrag();
68683
- }, [disabled, poolIdentity]);
68684
- (0, react.useEffect)(() => {
68685
- if (disabled && !pending) {
68686
- setSelection(null);
68687
- setResetOpen(false);
68688
- }
68689
- }, [disabled, pending]);
68690
- const candidates = [...available.values()].filter((model) => !pooled.has(modelKey(model)));
68691
- const query = search.trim().toLowerCase();
68692
- const filtered = candidates.filter((model) => `${model.label} ${model.provider} ${model.model}`.toLowerCase().includes(query));
68693
- const additions = [...selection ?? []].flatMap((key) => {
68694
- const model = available.get(key);
68695
- return model === void 0 || pooled.has(key) ? [] : [{
68696
- provider: model.provider,
68697
- model: model.model
68698
- }];
68699
- });
68700
- const closePicker = () => {
68701
- if (!pending) setSelection(null);
68702
- };
68703
- const addSelected = async () => {
68704
- if (disabled || additions.length === 0) return;
68705
- setSaveFailed(false);
68706
- if (await onChange([...pool, ...additions])) setSelection(null);
68707
- else setSaveFailed(true);
68708
- };
68709
- const closeReset = () => {
68710
- if (!pending) setResetOpen(false);
68711
- };
68712
- const confirmReset = async () => {
68713
- if (disabled || !resetOpen) return;
68714
- setResetFailed(false);
68715
- if (await onChange([])) setResetOpen(false);
68716
- else setResetFailed(true);
68717
- };
68718
- const commitOrder = (order, key) => {
68719
- if (locked) return;
68720
- onChange(order).then((saved) => {
68721
- if (saved) setAnnouncement(t("translation.modelReordered", {
68722
- model: available.get(key)?.label ?? order.find((model) => modelKey(model) === key)?.model ?? "",
68723
- priority: order.findIndex((model) => modelKey(model) === key) + 1
68724
- }));
68725
- });
68726
- };
68727
- const startDrag = (event, key) => {
68728
- if (locked || pool.length < 2 || event.button !== 0 || list.current === null) return;
68729
- event.preventDefault();
68730
- event.currentTarget.focus();
68731
- list.current.setPointerCapture(event.pointerId);
68732
- drag.current = {
68733
- pointerId: event.pointerId,
68734
- key,
68735
- startY: event.clientY,
68736
- original: pool,
68737
- order: pool
68738
- };
68739
- };
68740
- const rowAtPointer = (event) => {
68741
- const target = event.currentTarget.ownerDocument.elementFromPoint(event.clientX, event.clientY)?.closest("[data-codingns-translation-model-key]");
68742
- return target !== null && target !== void 0 && list.current?.contains(target) ? target : void 0;
68743
- };
68744
- const moveDrag = (event) => {
68745
- const current = drag.current;
68746
- const root = list.current;
68747
- if (locked || current === null || current.pointerId !== event.pointerId || root === null) return;
68748
- if (preview === null && Math.abs(event.clientY - current.startY) < 4) return;
68749
- event.preventDefault();
68750
- const rect = root.getBoundingClientRect();
68751
- if (event.clientY < rect.top + 24) root.scrollTop -= 12;
68752
- else if (event.clientY > rect.bottom - 24) root.scrollTop += 12;
68753
- const target = rowAtPointer(event);
68754
- if (target === void 0) return;
68755
- const targetIndex = current.order.findIndex((model) => modelKey(model) === target.dataset.codingnsTranslationModelKey);
68756
- const sourceIndex = current.order.findIndex((model) => modelKey(model) === current.key);
68757
- if (targetIndex < 0 || sourceIndex < 0 || targetIndex === sourceIndex) return;
68758
- const next = {
68759
- ...current,
68760
- order: moveModel(current.order, sourceIndex, targetIndex)
68761
- };
68762
- drag.current = next;
68763
- setPreview(next);
68764
- };
68765
- const finishDrag = (event) => {
68766
- const current = drag.current;
68767
- if (current === null || current.pointerId !== event.pointerId) return;
68768
- cancelDrag();
68769
- if (!locked && rowAtPointer(event) !== void 0 && JSON.stringify(current.order) !== JSON.stringify(current.original)) commitOrder(current.order, current.key);
68770
- };
68771
- const keyboardMove = (event, key) => {
68772
- if (event.key === "Escape" && drag.current !== null) {
68773
- event.stopPropagation();
68774
- cancelDrag();
68775
- return;
68776
- }
68777
- if (locked || drag.current !== null || ![
68778
- "ArrowUp",
68779
- "ArrowDown",
68780
- "Home",
68781
- "End"
68782
- ].includes(event.key)) return;
68783
- event.preventDefault();
68784
- const index = pool.findIndex((model) => modelKey(model) === key);
68785
- const target = event.key === "Home" ? 0 : event.key === "End" ? pool.length - 1 : index + (event.key === "ArrowUp" ? -1 : 1);
68786
- if (index >= 0 && target >= 0 && target < pool.length && target !== index) commitOrder(moveModel(pool, index, target), key);
68787
- };
68788
- return (0, react.createElement)("div", {
68789
- className: "codingns-translation-pool",
68790
- "aria-busy": pending
68791
- }, (0, react.createElement)("style", null, modelPoolCss), (0, react.createElement)("div", { className: "codingns-translation-pool-toolbar" }, (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, t(pool.length === 0 ? "translation.modelDefaultActive" : "translation.modelPoolCount", { count: pool.length })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68792
- type: "button",
68793
- variant: "outline",
68794
- size: "sm",
68795
- disabled: disabled || resetOpen,
68796
- icon: (0, react.createElement)(require_primitives_adapter.resolvePlusIcon(), { size: 14 }),
68797
- "aria-haspopup": "dialog",
68798
- "aria-expanded": pickerOpen,
68799
- onClick: () => {
68800
- if (!disabled && !resetOpen) {
68801
- setSearch("");
68802
- setSaveFailed(false);
68803
- setSelection(/* @__PURE__ */ new Set());
68804
- }
68805
- }
68806
- }, t("translation.modelAdd"))), pool.length === 0 ? (0, react.createElement)("div", { className: "codingns-translation-pool-empty" }, (0, react.createElement)(require_primitives_adapter.resolveDataIcon(), { size: 22 }), (0, react.createElement)("span", null, t("translation.modelPoolEmpty"))) : (0, react.createElement)("ol", {
68807
- ref: list,
68808
- className: "codingns-translation-pool-list",
68809
- "aria-label": t("translation.modelTitle"),
68810
- onPointerMove: moveDrag,
68811
- onPointerUp: finishDrag,
68812
- onPointerCancel: cancelDrag,
68813
- onLostPointerCapture: cancelDrag
68814
- }, ...(preview?.order ?? pool).map((model, index) => {
68815
- const key = modelKey(model);
68816
- const entry = available.get(key);
68817
- const label = entry?.label ?? `${model.provider} / ${model.model}`;
68818
- return (0, react.createElement)("li", {
68819
- key,
68820
- "data-codingns-translation-model-key": key,
68821
- className: `codingns-translation-pool-row${preview?.key === key ? " is-dragging" : ""}`
68822
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68823
- type: "button",
68824
- size: "sm",
68825
- disabled: locked || pool.length < 2,
68826
- className: "codingns-translation-pool-handle",
68827
- "aria-label": t("translation.modelDrag", { model: label }),
68828
- title: t("translation.modelDragHelp"),
68829
- onPointerDown: (event) => startDrag(event, key),
68830
- onKeyDown: (event) => keyboardMove(event, key)
68831
- }, (0, react.createElement)(DragHandleIcon)), (0, react.createElement)("span", {
68832
- className: "codingns-translation-pool-priority",
68833
- title: t("translation.modelPriority", { priority: index + 1 })
68834
- }, index + 1), (0, react.createElement)(ModelIdentity, {
68835
- model,
68836
- label,
68837
- t
68838
- }), catalog !== null && entry === void 0 && (0, react.createElement)("span", { className: "codingns-translation-pool-unavailable" }, t("translation.modelUnavailable")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68839
- type: "button",
68840
- size: "sm",
68841
- disabled: locked,
68842
- className: "codingns-translation-pool-remove",
68843
- "aria-label": t("translation.modelRemove", { model: label }),
68844
- title: t("translation.modelRemove", { model: label }),
68845
- onClick: () => {
68846
- if (!locked) onChange(pool.filter((item) => modelKey(item) !== key));
68847
- }
68848
- }, (0, react.createElement)(require_primitives_adapter.resolveAssistantControlIcon("close"), { size: 14 })));
68849
- })), (0, react.createElement)("div", { className: "codingns-translation-pool-toolbar" }, (0, react.createElement)("span", { style: {
68850
- ...require_theme.dshSettingsHelpStyle,
68851
- flex: 1
68852
- } }, t("translation.modelHelp")), pool.length > 0 && (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68853
- type: "button",
68854
- size: "sm",
68855
- disabled: disabled || pickerOpen,
68856
- style: { color: require_theme.dshThemeColor.error },
68857
- "aria-haspopup": "dialog",
68858
- "aria-expanded": resetOpen,
68859
- onClick: () => {
68860
- if (!locked) {
68861
- setResetFailed(false);
68862
- setResetOpen(true);
68863
- }
68864
- }
68865
- }, t("translation.modelFollowDefault"))), (0, react.createElement)("span", {
68866
- role: "status",
68867
- "aria-live": "polite",
68868
- className: "codingns-translation-pool-status"
68869
- }, announcement), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
68870
- open: pickerOpen,
68871
- onClose: closePicker,
68872
- title: t("translation.modelPickerTitle"),
68873
- closeLabel: t("translation.modelCancel"),
68874
- description: t("translation.modelPickerHelp"),
68875
- className: "codingns-translation-model-picker",
68876
- contentClassName: "codingns-translation-model-picker-content",
68877
- footer: (0, react.createElement)(react.Fragment, null, (0, react.createElement)("span", {
68878
- className: "codingns-translation-picker-count",
68879
- "aria-live": "polite",
68880
- style: require_theme.dshSettingsHelpStyle
68881
- }, t("translation.modelPickerCount", { count: additions.length })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68882
- type: "button",
68883
- variant: "outline",
68884
- disabled: pending,
68885
- onClick: closePicker
68886
- }, t("translation.modelCancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68887
- type: "button",
68888
- variant: "primary",
68889
- disabled: disabled || additions.length === 0,
68890
- onClick: () => {
68891
- addSelected();
68892
- }
68893
- }, t("translation.modelAddSelected", { count: additions.length })))
68894
- }, (0, react.createElement)("div", {
68895
- className: "codingns-translation-picker-body",
68896
- "aria-busy": pending
68897
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
68898
- type: "search",
68899
- value: search,
68900
- placeholder: t("translation.modelSearch"),
68901
- "aria-label": t("translation.modelSearch"),
68902
- "data-modal-autofocus": true,
68903
- disabled,
68904
- onChange: (event) => setSearch(event.currentTarget.value)
68905
- }), (0, react.createElement)("div", {
68906
- className: "codingns-translation-picker-list",
68907
- role: "group",
68908
- "aria-label": t("translation.modelPickerTitle")
68909
- }, ...filtered.map((model) => {
68910
- const key = modelKey(model);
68911
- return (0, react.createElement)("div", {
68912
- key,
68913
- className: `codingns-translation-picker-choice${selection?.has(key) ? " is-selected" : ""}`
68914
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
68915
- checked: selection?.has(key) === true,
68916
- disabled,
68917
- label: model.label,
68918
- onChange: (checked) => {
68919
- if (disabled) return;
68920
- setSelection((previous) => {
68921
- const next = new Set(previous);
68922
- if (checked) next.add(key);
68923
- else next.delete(key);
68924
- return next;
68925
- });
68926
- }
68927
- }), (0, react.createElement)("span", {
68928
- className: "codingns-translation-picker-provider",
68929
- style: require_theme.dshSettingsHelpStyle
68930
- }, t(isOfficialProvider(model.provider) ? "translation.modelOfficial" : "translation.modelThirdParty")));
68931
- }), filtered.length > 0 ? null : (0, react.createElement)("div", {
68932
- className: "codingns-translation-pool-empty",
68933
- role: "status"
68934
- }, t(catalog === null ? "translation.modelLoading" : candidates.length > 0 ? "translation.modelNoMatches" : available.size > 0 ? "translation.modelAllAdded" : "translation.modelEmpty"))), saveFailed && (0, react.createElement)("span", {
68935
- role: "alert",
68936
- style: {
68937
- ...require_theme.dshSettingsHelpStyle,
68938
- color: require_theme.dshThemeColor.error
68939
- }
68940
- }, t("translation.saveRejected")))), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
68941
- open: resetOpen,
68942
- onClose: closeReset,
68943
- title: t("translation.modelResetTitle"),
68944
- closeLabel: t("translation.modelCancel"),
68945
- description: t("translation.modelResetHelp", { count: pool.length }),
68946
- footer: (0, react.createElement)(react.Fragment, null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68947
- type: "button",
68948
- variant: "outline",
68949
- disabled: pending,
68950
- "data-modal-autofocus": true,
68951
- onClick: closeReset
68952
- }, t("translation.modelCancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
68953
- type: "button",
68954
- variant: "outline",
68955
- disabled,
68956
- style: { color: require_theme.dshThemeColor.error },
68957
- onClick: () => {
68958
- confirmReset();
68959
- }
68960
- }, t("translation.modelResetConfirm")))
68961
- }, resetFailed ? (0, react.createElement)("span", {
68962
- role: "alert",
68963
- style: {
68964
- ...require_theme.dshSettingsHelpStyle,
68965
- color: require_theme.dshThemeColor.error
68966
- }
68967
- }, t("translation.saveRejected")) : void 0));
68968
- }
68969
- function modelKey(model) {
68970
- return JSON.stringify([model.provider, model.model]);
68971
- }
68972
- function moveModel(pool, source, target) {
68973
- const next = [...pool];
68974
- const model = next.splice(source, 1)[0];
68975
- if (model !== void 0) next.splice(target, 0, model);
68976
- return next;
68977
- }
68978
- function isOfficialProvider(provider) {
68979
- return /^(?:deepseek(?:-official)?|official-deepseek)$/iu.test(provider.trim());
68980
- }
68981
- function ModelIdentity({ model, label, t }) {
68982
- const [provider, ...name] = label.split(" / ");
68983
- return (0, react.createElement)("div", {
68984
- className: "codingns-translation-pool-identity",
68985
- title: label
68986
- }, (0, react.createElement)("span", { className: "codingns-translation-pool-name" }, name.join(" / ") || model.model), (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, `${provider ?? model.provider} · ${t(isOfficialProvider(model.provider) ? "translation.modelOfficial" : "translation.modelThirdParty")}`));
68987
- }
68988
- function DragHandleIcon() {
68989
- return (0, react.createElement)("svg", {
68990
- width: 14,
68991
- height: 18,
68992
- viewBox: "0 0 14 18",
68993
- fill: "currentColor",
68994
- "aria-hidden": true,
68995
- focusable: false
68996
- }, ...[5, 9].flatMap((cx) => [
68997
- 4,
68998
- 9,
68999
- 14
69000
- ].map((cy) => (0, react.createElement)("circle", {
69001
- key: `${cx}:${cy}`,
69002
- cx,
69003
- cy,
69004
- r: 1
69005
- }))));
69006
- }
69007
- const modelPoolCss = `
69008
- .codingns-translation-pool{display:grid;gap:10px;min-width:0}
69009
- .codingns-translation-pool-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}
69010
- .codingns-translation-pool-list{list-style:none;margin:0;padding:0;max-height:352px;overflow:auto;overscroll-behavior:contain;border:.5px solid ${require_theme.dshThemeColor.menuBorder};border-radius:var(--dsw-radius-md,12px);background:${require_theme.dshThemeColor.pageBackground}}
69011
- .codingns-translation-pool-row{display:flex;align-items:center;gap:10px;min-height:64px;padding:8px 12px 8px 6px;box-sizing:border-box}
69012
- .codingns-translation-pool-row:not(:last-child){border-bottom:.5px solid ${require_theme.dshThemeColor.menuBorder}}
69013
- .codingns-translation-pool-row:hover{background:${require_theme.dshThemeColor.hoverBackground}}
69014
- .codingns-translation-pool-row.is-dragging{background:${require_theme.dshThemeColor.activeBackground};box-shadow:inset 2px 0 ${require_theme.dshThemeColor.accent}}
69015
- .codingns-translation-pool .codingns-translation-pool-handle{width:28px;flex:0 0 28px;padding:0;touch-action:none;cursor:grab;color:${require_theme.dshThemeColor.labelTertiary}}
69016
- .codingns-translation-pool .codingns-translation-pool-handle:active{cursor:grabbing}
69017
- .codingns-translation-pool .codingns-translation-pool-handle:disabled{cursor:default}
69018
- .codingns-translation-pool-priority{display:flex;align-items:center;justify-content:center;flex:0 0 24px;height:24px;border-radius:var(--dsw-radius-sm,8px);background:${require_theme.dshThemeColor.surfaceSubtle};color:${require_theme.dshThemeColor.labelSecondary};font-size:${require_theme.uiFontSize(12)};font-variant-numeric:tabular-nums}
69019
- .codingns-translation-pool-identity{display:grid;gap:2px;min-width:0;flex:1}
69020
- .codingns-translation-pool-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:${require_theme.dshThemeColor.labelPrimary};font-size:${require_theme.uiFontSize(13)};font-weight:500;line-height:20px}
69021
- .codingns-translation-pool-identity>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
69022
- .codingns-translation-pool .codingns-translation-pool-remove{flex:0 0 28px;width:28px;padding:0;color:${require_theme.dshThemeColor.labelTertiary}}
69023
- .codingns-translation-pool-unavailable{max-width:110px;flex-shrink:0;color:${require_theme.dshThemeColor.warning};font-size:${require_theme.uiFontSize(11)};line-height:16px}
69024
- .codingns-translation-pool-empty{display:flex;align-items:center;justify-content:center;gap:10px;padding:22px 14px;color:${require_theme.dshThemeColor.labelTertiary};background:${require_theme.dshThemeColor.surfaceSubtle};border-radius:var(--dsw-radius-md,12px);font-size:${require_theme.uiFontSize(12)};text-align:center;line-height:20px}
69025
- .codingns-translation-pool-status{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
69026
- .codingns-translation-model-picker{width:min(520px,100%);max-height:100%;color:${require_theme.dshThemeColor.labelPrimary}}
69027
- .codingns-translation-model-picker-content{min-height:0;overflow:auto}
69028
- .codingns-translation-picker-body{display:grid;gap:12px;padding-bottom:4px}
69029
- .codingns-translation-picker-list{display:grid;gap:6px;min-height:80px;max-height:320px;overflow:auto;overscroll-behavior:contain}
69030
- .codingns-translation-picker-choice{display:grid;gap:3px;padding:10px 12px;border:.5px solid ${require_theme.dshThemeColor.menuBorder};border-radius:var(--dsw-radius-sm,8px);background:${require_theme.dshThemeColor.pageBackground}}
69031
- .codingns-translation-picker-choice:hover,.codingns-translation-picker-choice.is-selected{background:${require_theme.dshThemeColor.hoverBackground}}
69032
- .codingns-translation-picker-choice>label{align-items:flex-start;gap:10px;overflow-wrap:anywhere}
69033
- .codingns-translation-picker-choice input{margin-top:2px}
69034
- .codingns-translation-picker-provider{padding-left:26px}
69035
- .codingns-translation-picker-count{margin-right:auto}
69036
- @media(max-width:480px){.codingns-translation-pool-row{gap:6px;padding-right:8px}.codingns-translation-pool-unavailable{max-width:70px}.codingns-translation-picker-choice{padding:10px}}
69037
- `;
69038
69830
  //#endregion
69039
69831
  //#region src/client/session-translation-rules.ts
69040
69832
  /** Only saved entries enter translation prompts; cancelled or failed edits stay local. */
@@ -70921,8 +71713,8 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${require_theme.dsh
70921
71713
  }, t(languageLabelKeys[language]))))), (0, react.createElement)("div", { style: {
70922
71714
  ...require_theme.dshSettingsSectionHeaderStyle,
70923
71715
  marginTop: 12
70924
- } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("translation.modelTitle"))), (0, react.createElement)(SessionTranslationModelPool, {
70925
- value,
71716
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("translation.modelTitle"))), (0, react.createElement)(ModelPriorityPool, {
71717
+ models: value.translationModels ?? (value.translationModel === void 0 ? [] : [value.translationModel]),
70926
71718
  catalog,
70927
71719
  disabled,
70928
71720
  pending: saving,
@@ -77255,7 +78047,8 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${require_theme.dsh
77255
78047
  "dsh-capabilities/host/assistant-llm-adapter.ts",
77256
78048
  "host/features/assistant-text-chat.ts",
77257
78049
  "dsh-capabilities/host/session-title-adapter.ts",
77258
- "host/features/session-title-optimization.ts"
78050
+ "host/features/session-title-optimization.ts",
78051
+ "host/features/git-management.ts"
77259
78052
  ]), route("assistant.agent", "assistant-agent-021", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["dsh-capabilities/host/assistant-agent-adapter.ts", "host/features/global-voice-rpc.ts"]), route("settings.store", "legacy-settings-scope", "host", ">=0.1.5-rc.3 <=0.1.6", "supported", ["host/settings.ts", "host/features/*"]), route("settings.store", "config-forms", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/settings.ts", "client/settings-bridge.ts"]), route("connection.rpc", "legacy-rpc-handler", "host", ">=0.1.5-rc.3 <=0.1.6", "supported", ["host/rpc.ts"]), route("connection.rpc", "peer-aware-rpc-handler", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/rpc.ts"]), route("connection.peer", "peer-scope", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/rpc.ts"]), route("ui.icon.plus", "fixed-plus-icon", "client", ">=0.1.5-rc.3 <=0.1.6", "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.plus", "regular-plus-icon", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.chevron", "fixed-chevron-icon", "client", ">=0.1.5-rc.3 <=0.1.6", "supported", ["client/terminal/ui.ts"]), route("ui.icon.chevron", "regular-chevron-icon", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/terminal/ui.ts"]), route("locale.runtime", "locale-runtime", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/locale.ts"]), route("theme.runtime", "theme-runtime", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/theme.ts"]), route("conversation.tool-call", "conversation-events", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/external-tool-stream.ts"]), route("sidebar.right", "sidebar-right-tabs", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/terminal/ui.ts"]), route("typert.remote", "remote-result", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/terminal/terminal-controller.ts", "client/terminal/model.ts"]), route("peer-host.store", "peer-host-store", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.handshake", "peer-host-handshake", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.http-proxy", "peer-host-http-proxy", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.ws-proxy", "peer-host-ws-proxy", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.aggregate", "peer-host-aggregate", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.relay-route", "peer-host-relay-route", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.native-navigation", "peer-host-native-navigation-legacy", "client", ">=0.1.5-rc.3 <=0.1.6", "deprecated", ["client/features/peer-host.ts"]), route("peer-host.native-navigation", "peer-host-native-navigation-modern", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/features/peer-host.ts"]), route("peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/features/peer-host.ts"]), route("settings.store", "settings-forms-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/settings.ts", "host/rpc.ts"]), route("connection.rpc", "connection-rpc-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/rpc.ts", "transport/dsh-transport.ts"]), route("connection.peer", "connection-peer-admission-020", "host", ">=0.2.0-rc.2 <=0.2.1-alpha.2", "supported", ["host/rpc.ts"]), route("connection.attachment", "connection-rpc-attachment-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/rpc.ts", "transport/dsh-transport.ts"]), route("connection.uplink", "connection-rpc-uplink-020", "host", ">=0.2.0-rc.2 <=0.2.1-alpha.2", "supported", ["host/rpc.ts", "transport/dsh-transport.ts"]), route("typert.remote", "remote-context-stream-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/terminal/terminal-controller.ts", "client/terminal/model.ts"]), route("typert.context", "typert-context-registry-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["typert.host.ts", "host/terminal/terminal-controller.ts"]), route("typert.stream", "typert-remote-stream-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["typert.host.ts", "typert.remote-client.ts"]), route("session.format-v4", "session-format-v4", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/native-session-bridge.ts", "host/session-migration-repair.ts"]), route("subagent.continuable", "subagent-continuable-020", "host", ">=0.2.0-rc.1 <=0.2.1-alpha.1", "supported", ["host/cli-adapters/session-store.ts", "host/cli-adapters/feature.ts"]), route("subagent.continuable", "subagent-activation-021", "host", ">=0.2.1-alpha.2", "supported", ["host/cli-adapters/native-team-subagent.ts", "host/cli-adapters/native-subagent-dispatch.ts"]), route("agent-team.native", "agent-team-native-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/cli-adapters/feature.ts", "host/cli-adapters/native-team-proxy.ts"]), route("agent-team.external-member", "agent-team-external-member-021", "host", ">=0.2.1-alpha.2 <=0.2.1-rc.2", "supported", ["host/cli-adapters/feature.ts", "host/cli-bridge/team-dispatch.ts"]), route("agent-team.external-lead", "agent-team-external-lead-021", "host", ">=0.2.1-alpha.2 <=0.2.1-rc.2", "supported", ["host/cli-adapters/feature.ts", "host/cli-bridge/team-dispatch.ts"]), route("ui.icon.plus", "regular-plus-icon-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.chevron", "regular-chevron-icon-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/terminal/ui.ts"]), route("locale.runtime", "locale-runtime-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/locale.ts"]), route("theme.runtime", "theme-runtime-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/theme.ts"]), route("theme.font-scale", "theme-font-scale-021", "client", ">=0.2.1-alpha.2", "supported", ["client/font-scale.ts", "client/index.ts"]), route("conversation.tool-call", "conversation-events-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/external-tool-stream.ts"]), route("conversation.draft-share", "conversation-draft-share-021", "client", ">=0.2.1-alpha.1 <=0.2.1-rc.2", "supported", ["client/terminal/ui.ts", "client/terminal/sharing.ts"]), route("conversation.interaction-translation", "interaction-presentation-021", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/session-translation-interactions.ts"]), route("sidebar.right", "sidebar-right-dock-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/terminal/ui.ts"]), route("typert.remote", "remote-context-stream-020-client", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/terminal/model.ts"]), route("typert.context", "typert-context-registry-020-client", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["typert.remote-client.ts", "client/terminal/model.ts"]), route("typert.stream", "typert-remote-stream-020-client", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["typert.remote-client.ts", "client/terminal/model.ts"]), route("client.boot-graph", "client-web-boot-graph-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/index.ts", "package.json"]), route("peer-host.native-navigation", "peer-host-native-navigation-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/features/peer-host.ts"]), route("peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["client/features/peer-host.ts"]), route("peer-host.store", "peer-host-store-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.handshake", "peer-host-handshake-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.http-proxy", "peer-host-http-proxy-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts", "host/modules/peer-host/quick-app-gateway.ts"]), route("peer-host.ws-proxy", "peer-host-ws-proxy-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.aggregate", "peer-host-aggregate-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.aggregated-transport", "peer-host-aggregated-transport-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["host/modules/peer-host/aggregated-host-transport.ts"]), route("peer-host.client-preboot-transport", "peer-host-client-preboot-transport-020", "client", require_native_workspace_store.DSH_COMPATIBILITY, "supported", [
77260
78053
  "bootstrap/index.ts",
77261
78054
  "host/index-injection.ts",
@@ -83276,5 +84069,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
83276
84069
  });
83277
84070
 
83278
84071
  })();
83279
- // codingns-client-revision: 75471ae1b8c6158ff3a696d9b8d4440efd9c6f8212760d2e2bdcf208a469d952
84072
+ // codingns-client-revision: c70e6c4185d35edabf441612e5012044ffdd0658ca60590d6c3b9e3bbf4a3d5a
83280
84073
  //# sourceMappingURL=bundle.js.map