@jingyi0605/codingns4dsh 0.2.1-beta.11 → 0.2.1-beta.12

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 (193) hide show
  1. package/README.en.md +7 -5
  2. package/README.md +9 -5
  3. package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +1 -1
  4. package/data/build/dist/bootstrap/index.d.ts +1 -1
  5. package/data/build/dist/client/bundle.js +2280 -1495
  6. package/data/build/dist/client/bundle.js.map +1 -1
  7. package/data/build/dist/client/cli-slots.d.ts +3 -2
  8. package/data/build/dist/client/cli-slots.d.ts.map +1 -1
  9. package/data/build/dist/client/cli-slots.js +29 -5
  10. package/data/build/dist/client/cli-slots.js.map +1 -1
  11. package/data/build/dist/client/client.assistant-configuration-view.js +5 -5
  12. package/data/build/dist/client/client.assistant-configuration-view.js.map +1 -1
  13. package/data/build/dist/client/client.moss-voice-output.js +0 -166
  14. package/data/build/dist/client/client.moss-voice-output.js.map +1 -1
  15. package/data/build/dist/client/client.native-workspace-store.js +4 -4
  16. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  17. package/data/build/dist/client/client.react-dom.js +166 -0
  18. package/data/build/dist/client/client.react-dom.js.map +1 -1
  19. package/data/build/dist/client/client.session-translation.js +9 -1
  20. package/data/build/dist/client/client.session-translation.js.map +1 -1
  21. package/data/build/dist/client/client.transport.js +46 -0
  22. package/data/build/dist/client/client.transport.js.map +1 -1
  23. package/data/build/dist/client/conversation-translation-settings.d.ts +10 -0
  24. package/data/build/dist/client/conversation-translation-settings.d.ts.map +1 -0
  25. package/data/build/dist/client/conversation-translation-settings.js +52 -0
  26. package/data/build/dist/client/conversation-translation-settings.js.map +1 -0
  27. package/data/build/dist/client/desktop-assistant.js +512 -439
  28. package/data/build/dist/client/features/cli-adapters.js +1 -1
  29. package/data/build/dist/client/features/cli-adapters.js.map +1 -1
  30. package/data/build/dist/client/features/session-translation.d.ts.map +1 -1
  31. package/data/build/dist/client/features/session-translation.js +7 -1
  32. package/data/build/dist/client/features/session-translation.js.map +1 -1
  33. package/data/build/dist/client/locales/panels.d.ts.map +1 -1
  34. package/data/build/dist/client/locales/panels.js +46 -0
  35. package/data/build/dist/client/locales/panels.js.map +1 -1
  36. package/data/build/dist/client/session-translation-chat.d.ts +9 -3
  37. package/data/build/dist/client/session-translation-chat.d.ts.map +1 -1
  38. package/data/build/dist/client/session-translation-chat.js +146 -48
  39. package/data/build/dist/client/session-translation-chat.js.map +1 -1
  40. package/data/build/dist/client/session-translation-pending-dom.d.ts +1 -1
  41. package/data/build/dist/client/session-translation-pending-dom.d.ts.map +1 -1
  42. package/data/build/dist/client/session-translation-pending-dom.js +4 -4
  43. package/data/build/dist/client/session-translation-pending-dom.js.map +1 -1
  44. package/data/build/dist/client/session-translation-retry.d.ts +16 -0
  45. package/data/build/dist/client/session-translation-retry.d.ts.map +1 -0
  46. package/data/build/dist/client/session-translation-retry.js +66 -0
  47. package/data/build/dist/client/session-translation-retry.js.map +1 -0
  48. package/data/build/dist/client/session-translation-rules.d.ts +13 -0
  49. package/data/build/dist/client/session-translation-rules.d.ts.map +1 -0
  50. package/data/build/dist/client/session-translation-rules.js +58 -0
  51. package/data/build/dist/client/session-translation-rules.js.map +1 -0
  52. package/data/build/dist/client/style.css +276 -276
  53. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.d.ts.map +1 -1
  54. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.js +4 -13
  55. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.js.map +1 -1
  56. package/data/build/dist/dsh-capabilities/client/interaction-text-dom.js +1 -1
  57. package/data/build/dist/dsh-capabilities/client/interaction-text-dom.js.map +1 -1
  58. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.d.ts +19 -0
  59. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.d.ts.map +1 -0
  60. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.js +39 -0
  61. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.js.map +1 -0
  62. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.d.ts +2 -0
  63. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.d.ts.map +1 -1
  64. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.js +28 -0
  65. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.js.map +1 -1
  66. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.d.ts +10 -0
  67. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.d.ts.map +1 -0
  68. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.js +34 -0
  69. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.js.map +1 -0
  70. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.d.ts +21 -0
  71. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.d.ts.map +1 -0
  72. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.js +11 -0
  73. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.js.map +1 -0
  74. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.d.ts +17 -0
  75. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.d.ts.map +1 -0
  76. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.js +37 -0
  77. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.js.map +1 -0
  78. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts +17 -0
  79. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts.map +1 -0
  80. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js +45 -0
  81. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js.map +1 -0
  82. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.d.ts +28 -0
  83. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.d.ts.map +1 -0
  84. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.js +31 -0
  85. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.js.map +1 -0
  86. package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
  87. package/data/build/dist/dsh-capabilities/matrix.js +12 -4
  88. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  89. package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
  90. package/data/build/dist/dsh-capabilities/routes.js +25 -5
  91. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  92. package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
  93. package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
  94. package/data/build/dist/dsh-capabilities/types.js.map +1 -1
  95. package/data/build/dist/host/cli-adapters/antigravity-driver.js +1 -1
  96. package/data/build/dist/host/cli-adapters/antigravity-driver.js.map +1 -1
  97. package/data/build/dist/host/cli-adapters/attachment-utils.d.ts +4 -3
  98. package/data/build/dist/host/cli-adapters/attachment-utils.d.ts.map +1 -1
  99. package/data/build/dist/host/cli-adapters/attachment-utils.js +9 -8
  100. package/data/build/dist/host/cli-adapters/attachment-utils.js.map +1 -1
  101. package/data/build/dist/host/cli-adapters/claude-driver.js +1 -1
  102. package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
  103. package/data/build/dist/host/cli-adapters/command-code-driver.js +1 -1
  104. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  105. package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
  106. package/data/build/dist/host/cli-adapters/driver.d.ts.map +1 -1
  107. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +2 -0
  108. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  109. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +11 -3
  110. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  111. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  112. package/data/build/dist/host/cli-adapters/feature.js +154 -68
  113. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  114. package/data/build/dist/host/cli-adapters/gemini-driver.js +1 -1
  115. package/data/build/dist/host/cli-adapters/gemini-driver.js.map +1 -1
  116. package/data/build/dist/host/cli-adapters/grok-driver.d.ts +1 -0
  117. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  118. package/data/build/dist/host/cli-adapters/grok-driver.js +128 -40
  119. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  120. package/data/build/dist/host/cli-adapters/kimi-driver.js +2 -2
  121. package/data/build/dist/host/cli-adapters/kimi-driver.js.map +1 -1
  122. package/data/build/dist/host/cli-adapters/mcode-driver.js +1 -1
  123. package/data/build/dist/host/cli-adapters/mcode-driver.js.map +1 -1
  124. package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts.map +1 -1
  125. package/data/build/dist/host/cli-adapters/native-team-subagent.js +2 -1
  126. package/data/build/dist/host/cli-adapters/native-team-subagent.js.map +1 -1
  127. package/data/build/dist/host/cli-adapters/pi-driver.js +1 -1
  128. package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
  129. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  130. package/data/build/dist/host/cli-adapters/registry.js +23 -16
  131. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  132. package/data/build/dist/host/cli-adapters/zcode-driver.js +1 -1
  133. package/data/build/dist/host/cli-adapters/zcode-driver.js.map +1 -1
  134. package/data/build/dist/host/features/global-voice-rpc.d.ts.map +1 -1
  135. package/data/build/dist/host/features/global-voice-rpc.js +2 -3
  136. package/data/build/dist/host/features/global-voice-rpc.js.map +1 -1
  137. package/data/build/dist/host/features/peer-host.js +6 -6
  138. package/data/build/dist/host/features/peer-host.js.map +1 -1
  139. package/data/build/dist/host/features/session-prompt-translation.d.ts +10 -0
  140. package/data/build/dist/host/features/session-prompt-translation.d.ts.map +1 -0
  141. package/data/build/dist/host/features/session-prompt-translation.js +197 -0
  142. package/data/build/dist/host/features/session-prompt-translation.js.map +1 -0
  143. package/data/build/dist/host/features/session-translation-protection.d.ts +6 -1
  144. package/data/build/dist/host/features/session-translation-protection.d.ts.map +1 -1
  145. package/data/build/dist/host/features/session-translation-protection.js +23 -5
  146. package/data/build/dist/host/features/session-translation-protection.js.map +1 -1
  147. package/data/build/dist/host/features/session-translation-recovery.d.ts +20 -0
  148. package/data/build/dist/host/features/session-translation-recovery.d.ts.map +1 -0
  149. package/data/build/dist/host/features/session-translation-recovery.js +122 -0
  150. package/data/build/dist/host/features/session-translation-recovery.js.map +1 -0
  151. package/data/build/dist/host/features/session-translation-service.d.ts +5 -2
  152. package/data/build/dist/host/features/session-translation-service.d.ts.map +1 -1
  153. package/data/build/dist/host/features/session-translation-service.js +60 -16
  154. package/data/build/dist/host/features/session-translation-service.js.map +1 -1
  155. package/data/build/dist/host/features/session-translation.d.ts.map +1 -1
  156. package/data/build/dist/host/features/session-translation.js +4 -1
  157. package/data/build/dist/host/features/session-translation.js.map +1 -1
  158. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts +2 -2
  159. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts.map +1 -1
  160. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js +10 -9
  161. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js.map +1 -1
  162. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.d.ts +3 -3
  163. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.d.ts.map +1 -1
  164. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.js +26 -14
  165. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.js.map +1 -1
  166. package/data/build/dist/host/native-session-bridge.d.ts +2 -1
  167. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  168. package/data/build/dist/host/native-session-bridge.js +5 -13
  169. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  170. package/data/build/dist/host/rpc.d.ts.map +1 -1
  171. package/data/build/dist/host/rpc.js +14 -8
  172. package/data/build/dist/host/rpc.js.map +1 -1
  173. package/data/build/dist/host/settings.d.ts.map +1 -1
  174. package/data/build/dist/host/settings.js +5 -1
  175. package/data/build/dist/host/settings.js.map +1 -1
  176. package/data/build/dist/shared/attachment-prompts.d.ts +11 -0
  177. package/data/build/dist/shared/attachment-prompts.d.ts.map +1 -0
  178. package/data/build/dist/shared/attachment-prompts.js +17 -0
  179. package/data/build/dist/shared/attachment-prompts.js.map +1 -0
  180. package/data/build/dist/shared/contracts/cli-adapter.d.ts +8 -1
  181. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  182. package/data/build/dist/shared/contracts/errors.d.ts +2 -2
  183. package/data/build/dist/shared/contracts/session-translation.d.ts +13 -0
  184. package/data/build/dist/shared/contracts/session-translation.d.ts.map +1 -1
  185. package/data/build/dist/shared/contracts/session-translation.js +10 -0
  186. package/data/build/dist/shared/contracts/session-translation.js.map +1 -1
  187. package/data/build/dist/shared/contracts/version.d.ts +4 -4
  188. package/data/build/dist/shared/contracts/version.js +3 -3
  189. package/package.json +35 -34
  190. package/profile/README.md +2 -2
  191. package/profile/package.json +3 -3
  192. package/profile/version.json +3 -3
  193. package/version.json +3 -3
@@ -7554,150 +7554,8 @@ window.__ModuleLoader__.load({
7554
7554
  factory: () => { const require = __codingnsOwnerRequire;
7555
7555
  var module = { exports: {} };
7556
7556
  var exports = module.exports;
7557
- const require_theme = require("@jingyi0605/codingns4dsh/client.theme.js");
7558
7557
  const require_manager = require("@jingyi0605/codingns4dsh/client.manager.js");
7559
7558
  const require_primitives_adapter = require("@jingyi0605/codingns4dsh/client.primitives-adapter.js");
7560
- let react = require("react");
7561
- //#region src/client/settings-controls.ts
7562
- const settingsControlClass = {
7563
- switch: "codingns4dsh-settings-switch",
7564
- track: "codingns4dsh-settings-switch-track",
7565
- thumb: "codingns4dsh-settings-switch-thumb",
7566
- iconButton: "codingns4dsh-settings-icon-button"
7567
- };
7568
- /** 模块使用主开关,子设置使用更小、更轻的开关;保留 checkbox 的标签与键盘语义。 */
7569
- function SettingsSwitch(props) {
7570
- (0, react.useEffect)(() => retainSettingsControlStyles(), []);
7571
- const { variant = "setting", ...inputProps } = props;
7572
- const width = variant === "module" ? 36 : 28;
7573
- return (0, react.createElement)("span", {
7574
- className: settingsControlClass.switch,
7575
- "data-variant": variant,
7576
- style: {
7577
- position: "relative",
7578
- display: "inline-flex",
7579
- alignItems: "center",
7580
- flex: `0 0 ${width}px`,
7581
- width,
7582
- height: 28,
7583
- marginLeft: "auto"
7584
- }
7585
- }, (0, react.createElement)("input", {
7586
- type: "checkbox",
7587
- role: "switch",
7588
- ...inputProps,
7589
- style: {
7590
- position: "absolute",
7591
- inset: 0,
7592
- width: "100%",
7593
- height: "100%",
7594
- margin: 0,
7595
- opacity: 0,
7596
- cursor: props.disabled ? "not-allowed" : "pointer",
7597
- zIndex: 1
7598
- }
7599
- }), (0, react.createElement)("span", {
7600
- className: settingsControlClass.track,
7601
- "aria-hidden": true
7602
- }, (0, react.createElement)("span", { className: settingsControlClass.thumb })));
7603
- }
7604
- /** 文案占据剩余宽度;右侧操作不收缩,长说明和窄屏都不会移动开关。 */
7605
- function SettingsToggleRow({ label, description, checked, disabled, onChange, actions, style }) {
7606
- const id = (0, react.useId)();
7607
- return (0, react.createElement)("div", { style: {
7608
- ...require_theme.dshSettingsListRowStyle,
7609
- ...style
7610
- } }, (0, react.createElement)("label", {
7611
- htmlFor: id,
7612
- style: {
7613
- flex: "1 1 auto",
7614
- minWidth: 0,
7615
- cursor: disabled ? "not-allowed" : "pointer",
7616
- overflowWrap: "anywhere"
7617
- }
7618
- }, (0, react.createElement)("span", { style: {
7619
- display: "block",
7620
- fontSize: require_theme.uiFontSize(13),
7621
- fontWeight: 500,
7622
- lineHeight: 1.4
7623
- } }, label), description === void 0 ? null : (0, react.createElement)("span", { style: {
7624
- display: "block",
7625
- marginTop: 3,
7626
- ...require_theme.dshSettingsHelpStyle
7627
- } }, description)), (0, react.createElement)("span", { style: {
7628
- display: "inline-flex",
7629
- alignItems: "center",
7630
- gap: 10,
7631
- flex: "0 0 auto",
7632
- marginLeft: "auto"
7633
- } }, actions, (0, react.createElement)(SettingsSwitch, {
7634
- id,
7635
- "aria-label": label,
7636
- checked,
7637
- disabled,
7638
- onChange: (event) => onChange(event.currentTarget.checked)
7639
- })));
7640
- }
7641
- /** 图标按钮采用 DSH 的紧凑中性表面,交互态由共享样式表提供。 */
7642
- const settingsIconButtonStyle = {
7643
- display: "inline-flex",
7644
- alignItems: "center",
7645
- justifyContent: "center",
7646
- flex: "0 0 32px",
7647
- width: 32,
7648
- height: 32,
7649
- padding: 0,
7650
- boxSizing: "border-box",
7651
- border: 0,
7652
- borderRadius: "var(--dsw-radius-sm, 6px)",
7653
- color: require_theme.dshThemeColor.labelSecondary,
7654
- background: "transparent",
7655
- cursor: "pointer"
7656
- };
7657
- /** 各独立面板共享一份样式,最后一个开关卸载时释放,兼容 React 严格模式的重复挂载。 */
7658
- const retainedStyles = /* @__PURE__ */ new WeakMap();
7659
- function retainSettingsControlStyles() {
7660
- if (typeof document === "undefined") return () => void 0;
7661
- const dom = document;
7662
- let state = retainedStyles.get(dom);
7663
- if (state === void 0) {
7664
- const element = dom.createElement("style");
7665
- element.dataset.plugin = "codingns4dsh";
7666
- element.dataset.pluginCss = "codingns4dsh-settings-controls";
7667
- element.textContent = settingsControlCss;
7668
- dom.head.appendChild(element);
7669
- state = {
7670
- element,
7671
- users: 0
7672
- };
7673
- retainedStyles.set(dom, state);
7674
- }
7675
- const retained = state;
7676
- retained.users += 1;
7677
- return () => {
7678
- retained.users -= 1;
7679
- if (retained.users > 0) return;
7680
- retained.element.remove();
7681
- retainedStyles.delete(dom);
7682
- };
7683
- }
7684
- const settingsControlCss = `
7685
- .${settingsControlClass.switch}{--codingns-switch-height:16px;--codingns-switch-thumb:12px;--codingns-switch-travel:12px;--codingns-switch-active:var(--dsw-alias-button-info-fill);--codingns-switch-active-thumb:var(--dsw-static-neutral-00)}
7686
- .${settingsControlClass.switch}[data-variant="module"]{--codingns-switch-height:20px;--codingns-switch-thumb:16px;--codingns-switch-travel:16px;--codingns-switch-active:var(--dsw-alias-brand-primary);--codingns-switch-active-thumb:var(--dsw-alias-label-primary-foreground)}
7687
- .${settingsControlClass.track}{box-sizing:border-box;display:block;width:100%;height:var(--codingns-switch-height);padding:2px;border:0;border-radius:999px;corner-shape:round;background:var(--dsw-alias-border-l3);pointer-events:none;transition:background 120ms ease}
7688
- .${settingsControlClass.thumb}{display:block;width:var(--codingns-switch-thumb);height:var(--codingns-switch-thumb);border-radius:50%;corner-shape:round;background:var(--dsw-alias-switch-thumb);transition:transform 120ms ease,background 120ms ease}
7689
- .${settingsControlClass.switch}>input:checked+.${settingsControlClass.track}{background:var(--codingns-switch-active)}
7690
- .${settingsControlClass.switch}>input:checked+.${settingsControlClass.track}>.${settingsControlClass.thumb}{background:var(--codingns-switch-active-thumb);transform:translateX(var(--codingns-switch-travel))}
7691
- .${settingsControlClass.switch}>input:disabled+.${settingsControlClass.track}{opacity:.5}
7692
- .${settingsControlClass.switch}>input:disabled{cursor:not-allowed!important}
7693
- .${settingsControlClass.switch}>input:focus-visible+.${settingsControlClass.track}{outline:${require_theme.dshThemeColor.focusRing};outline-offset:3px}
7694
- .${settingsControlClass.iconButton}:hover:not(:disabled){color:${require_theme.dshThemeColor.labelPrimary};background:${require_theme.dshThemeColor.hoverBackground}}
7695
- .${settingsControlClass.iconButton}:active:not(:disabled){background:${require_theme.dshThemeColor.activeBackground}}
7696
- .${settingsControlClass.iconButton}:focus-visible{outline:${require_theme.dshThemeColor.focusRing};outline-offset:2px}
7697
- .${settingsControlClass.iconButton}:disabled{opacity:.5;cursor:not-allowed}
7698
- @media (prefers-reduced-motion:reduce){.${settingsControlClass.track},.${settingsControlClass.thumb}{transition:none}}
7699
- `;
7700
- //#endregion
7701
7559
  //#region src/client/peer-host-color.ts
7702
7560
  /**
7703
7561
  * 工作区标签配色的推导与缓存。
@@ -8070,18 +7928,6 @@ window.__ModuleLoader__.load({
8070
7928
  return MossVoiceOutput;
8071
7929
  }
8072
7930
  });
8073
- Object.defineProperty(exports, "SettingsSwitch", {
8074
- enumerable: true,
8075
- get: function() {
8076
- return SettingsSwitch;
8077
- }
8078
- });
8079
- Object.defineProperty(exports, "SettingsToggleRow", {
8080
- enumerable: true,
8081
- get: function() {
8082
- return SettingsToggleRow;
8083
- }
8084
- });
8085
7931
  Object.defineProperty(exports, "peerHostTagStyle", {
8086
7932
  enumerable: true,
8087
7933
  get: function() {
@@ -8100,18 +7946,6 @@ window.__ModuleLoader__.load({
8100
7946
  return sanitizeVoiceDiagnosticFields;
8101
7947
  }
8102
7948
  });
8103
- Object.defineProperty(exports, "settingsControlClass", {
8104
- enumerable: true,
8105
- get: function() {
8106
- return settingsControlClass;
8107
- }
8108
- });
8109
- Object.defineProperty(exports, "settingsIconButtonStyle", {
8110
- enumerable: true,
8111
- get: function() {
8112
- return settingsIconButtonStyle;
8113
- }
8114
- });
8115
7949
  Object.defineProperty(exports, "voiceDiagnosticError", {
8116
7950
  enumerable: true,
8117
7951
  get: function() {
@@ -8138,7 +7972,7 @@ window.__ModuleLoader__.load({
8138
7972
  const require_session_translation = require("@jingyi0605/codingns4dsh/client.session-translation.js");
8139
7973
  //#region src/shared/contracts/version.ts
8140
7974
  /** 当前经过完整验证的 DSH 版本;源文件由根目录 version.json 同步。 */
8141
- const DSH_VERSION = "0.2.1-alpha.2";
7975
+ const DSH_VERSION = "0.2.1-alpha.3";
8142
7976
  /**
8143
7977
  * 插件正式验证的 DSH 版本范围,覆盖 rc.2 到当前验证的 alpha.2。
8144
7978
  *
@@ -8151,7 +7985,7 @@ window.__ModuleLoader__.load({
8151
7985
  * 这里保留明确上界,是为了让 npm/DSH 安装期也能识别 0.2.1-alpha.2 这个跨 patch
8152
7986
  * 预发布版本;出现新的 API 世代或结构变化时,应重新验证并更新范围与能力路由。
8153
7987
  */
8154
- const DSH_COMPATIBILITY = ">=0.2.0-rc.2 <=0.2.1-alpha.2";
7988
+ const DSH_COMPATIBILITY = ">=0.2.0-rc.2 <=0.2.1-alpha.3";
8155
7989
  /**
8156
7990
  * 兼容范围下界,即插件仍然接受的最低 DSH 版本。
8157
7991
  *
@@ -8160,7 +7994,7 @@ window.__ModuleLoader__.load({
8160
7994
  * “不支持的 DSH 版本”,把仅仅缺少启动页注入的页面误判为宿主不兼容。
8161
7995
  */
8162
7996
  function minimumSupportedDshVersion() {
8163
- return /^>=([^ ]+)/u.exec(">=0.2.0-rc.2 <=0.2.1-alpha.2")?.[1] ?? "0.2.1-alpha.2";
7997
+ return /^>=([^ ]+)/u.exec(">=0.2.0-rc.2 <=0.2.1-alpha.3")?.[1] ?? "0.2.1-alpha.3";
8164
7998
  }
8165
7999
  /** Host 注入到浏览器页面的真实 DSH 版本全局字段。 */
8166
8000
  const CODINGNS_DSH_VERSION_GLOBAL = "__CODINGNS_DSH_VERSION__";
@@ -8169,7 +8003,7 @@ window.__ModuleLoader__.load({
8169
8003
  return /^0\.1\.5(?:-|$)/u.test(version);
8170
8004
  }
8171
8005
  /** Codingns4DSH 插件自身的 npm 版本。 */
8172
- const CODINGNS_VERSION = "0.2.1-beta.11";
8006
+ const CODINGNS_VERSION = "0.2.1-beta.12";
8173
8007
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
8174
8008
  function isDshVersionCompatible(version) {
8175
8009
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -9222,6 +9056,148 @@ window.__ModuleLoader__.load({
9222
9056
  var module = { exports: {} };
9223
9057
  var exports = module.exports;
9224
9058
  const require_rolldown_runtime = require("@jingyi0605/codingns4dsh/client.rolldown-runtime.js");
9059
+ const require_theme = require("@jingyi0605/codingns4dsh/client.theme.js");
9060
+ let react = require("react");
9061
+ //#region src/client/settings-controls.ts
9062
+ const settingsControlClass = {
9063
+ switch: "codingns4dsh-settings-switch",
9064
+ track: "codingns4dsh-settings-switch-track",
9065
+ thumb: "codingns4dsh-settings-switch-thumb",
9066
+ iconButton: "codingns4dsh-settings-icon-button"
9067
+ };
9068
+ /** 模块使用主开关,子设置使用更小、更轻的开关;保留 checkbox 的标签与键盘语义。 */
9069
+ function SettingsSwitch(props) {
9070
+ (0, react.useEffect)(() => retainSettingsControlStyles(), []);
9071
+ const { variant = "setting", ...inputProps } = props;
9072
+ const width = variant === "module" ? 36 : 28;
9073
+ return (0, react.createElement)("span", {
9074
+ className: settingsControlClass.switch,
9075
+ "data-variant": variant,
9076
+ style: {
9077
+ position: "relative",
9078
+ display: "inline-flex",
9079
+ alignItems: "center",
9080
+ flex: `0 0 ${width}px`,
9081
+ width,
9082
+ height: 28,
9083
+ marginLeft: "auto"
9084
+ }
9085
+ }, (0, react.createElement)("input", {
9086
+ type: "checkbox",
9087
+ role: "switch",
9088
+ ...inputProps,
9089
+ style: {
9090
+ position: "absolute",
9091
+ inset: 0,
9092
+ width: "100%",
9093
+ height: "100%",
9094
+ margin: 0,
9095
+ opacity: 0,
9096
+ cursor: props.disabled ? "not-allowed" : "pointer",
9097
+ zIndex: 1
9098
+ }
9099
+ }), (0, react.createElement)("span", {
9100
+ className: settingsControlClass.track,
9101
+ "aria-hidden": true
9102
+ }, (0, react.createElement)("span", { className: settingsControlClass.thumb })));
9103
+ }
9104
+ /** 文案占据剩余宽度;右侧操作不收缩,长说明和窄屏都不会移动开关。 */
9105
+ function SettingsToggleRow({ label, description, checked, disabled, onChange, actions, style }) {
9106
+ const id = (0, react.useId)();
9107
+ return (0, react.createElement)("div", { style: {
9108
+ ...require_theme.dshSettingsListRowStyle,
9109
+ ...style
9110
+ } }, (0, react.createElement)("label", {
9111
+ htmlFor: id,
9112
+ style: {
9113
+ flex: "1 1 auto",
9114
+ minWidth: 0,
9115
+ cursor: disabled ? "not-allowed" : "pointer",
9116
+ overflowWrap: "anywhere"
9117
+ }
9118
+ }, (0, react.createElement)("span", { style: {
9119
+ display: "block",
9120
+ fontSize: require_theme.uiFontSize(13),
9121
+ fontWeight: 500,
9122
+ lineHeight: 1.4
9123
+ } }, label), description === void 0 ? null : (0, react.createElement)("span", { style: {
9124
+ display: "block",
9125
+ marginTop: 3,
9126
+ ...require_theme.dshSettingsHelpStyle
9127
+ } }, description)), (0, react.createElement)("span", { style: {
9128
+ display: "inline-flex",
9129
+ alignItems: "center",
9130
+ gap: 10,
9131
+ flex: "0 0 auto",
9132
+ marginLeft: "auto"
9133
+ } }, actions, (0, react.createElement)(SettingsSwitch, {
9134
+ id,
9135
+ "aria-label": label,
9136
+ checked,
9137
+ disabled,
9138
+ onChange: (event) => onChange(event.currentTarget.checked)
9139
+ })));
9140
+ }
9141
+ /** 图标按钮采用 DSH 的紧凑中性表面,交互态由共享样式表提供。 */
9142
+ const settingsIconButtonStyle = {
9143
+ display: "inline-flex",
9144
+ alignItems: "center",
9145
+ justifyContent: "center",
9146
+ flex: "0 0 32px",
9147
+ width: 32,
9148
+ height: 32,
9149
+ padding: 0,
9150
+ boxSizing: "border-box",
9151
+ border: 0,
9152
+ borderRadius: "var(--dsw-radius-sm, 6px)",
9153
+ color: require_theme.dshThemeColor.labelSecondary,
9154
+ background: "transparent",
9155
+ cursor: "pointer"
9156
+ };
9157
+ /** 各独立面板共享一份样式,最后一个开关卸载时释放,兼容 React 严格模式的重复挂载。 */
9158
+ const retainedStyles = /* @__PURE__ */ new WeakMap();
9159
+ function retainSettingsControlStyles() {
9160
+ if (typeof document === "undefined") return () => void 0;
9161
+ const dom = document;
9162
+ let state = retainedStyles.get(dom);
9163
+ if (state === void 0) {
9164
+ const element = dom.createElement("style");
9165
+ element.dataset.plugin = "codingns4dsh";
9166
+ element.dataset.pluginCss = "codingns4dsh-settings-controls";
9167
+ element.textContent = settingsControlCss;
9168
+ dom.head.appendChild(element);
9169
+ state = {
9170
+ element,
9171
+ users: 0
9172
+ };
9173
+ retainedStyles.set(dom, state);
9174
+ }
9175
+ const retained = state;
9176
+ retained.users += 1;
9177
+ return () => {
9178
+ retained.users -= 1;
9179
+ if (retained.users > 0) return;
9180
+ retained.element.remove();
9181
+ retainedStyles.delete(dom);
9182
+ };
9183
+ }
9184
+ const settingsControlCss = `
9185
+ .${settingsControlClass.switch}{--codingns-switch-height:16px;--codingns-switch-thumb:12px;--codingns-switch-travel:12px;--codingns-switch-active:var(--dsw-alias-button-info-fill);--codingns-switch-active-thumb:var(--dsw-static-neutral-00)}
9186
+ .${settingsControlClass.switch}[data-variant="module"]{--codingns-switch-height:20px;--codingns-switch-thumb:16px;--codingns-switch-travel:16px;--codingns-switch-active:var(--dsw-alias-brand-primary);--codingns-switch-active-thumb:var(--dsw-alias-label-primary-foreground)}
9187
+ .${settingsControlClass.track}{box-sizing:border-box;display:block;width:100%;height:var(--codingns-switch-height);padding:2px;border:0;border-radius:999px;corner-shape:round;background:var(--dsw-alias-border-l3);pointer-events:none;transition:background 120ms ease}
9188
+ .${settingsControlClass.thumb}{display:block;width:var(--codingns-switch-thumb);height:var(--codingns-switch-thumb);border-radius:50%;corner-shape:round;background:var(--dsw-alias-switch-thumb);transition:transform 120ms ease,background 120ms ease}
9189
+ .${settingsControlClass.switch}>input:checked+.${settingsControlClass.track}{background:var(--codingns-switch-active)}
9190
+ .${settingsControlClass.switch}>input:checked+.${settingsControlClass.track}>.${settingsControlClass.thumb}{background:var(--codingns-switch-active-thumb);transform:translateX(var(--codingns-switch-travel))}
9191
+ .${settingsControlClass.switch}>input:disabled+.${settingsControlClass.track}{opacity:.5}
9192
+ .${settingsControlClass.switch}>input:disabled{cursor:not-allowed!important}
9193
+ .${settingsControlClass.switch}>input:focus-visible+.${settingsControlClass.track}{outline:${require_theme.dshThemeColor.focusRing};outline-offset:3px}
9194
+ .${settingsControlClass.iconButton}:hover:not(:disabled){color:${require_theme.dshThemeColor.labelPrimary};background:${require_theme.dshThemeColor.hoverBackground}}
9195
+ .${settingsControlClass.iconButton}:active:not(:disabled){background:${require_theme.dshThemeColor.activeBackground}}
9196
+ .${settingsControlClass.iconButton}:focus-visible{outline:${require_theme.dshThemeColor.focusRing};outline-offset:2px}
9197
+ .${settingsControlClass.iconButton}:disabled{opacity:.5;cursor:not-allowed}
9198
+ @media (prefers-reduced-motion:reduce){.${settingsControlClass.track},.${settingsControlClass.thumb}{transition:none}}
9199
+ `;
9200
+ //#endregion
9225
9201
  //#region node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
9226
9202
  /**
9227
9203
  * @license React
@@ -16170,12 +16146,36 @@ window.__ModuleLoader__.load({
16170
16146
  module.exports = require_react_dom_production_min();
16171
16147
  }));
16172
16148
  //#endregion
16149
+ Object.defineProperty(exports, "SettingsSwitch", {
16150
+ enumerable: true,
16151
+ get: function() {
16152
+ return SettingsSwitch;
16153
+ }
16154
+ });
16155
+ Object.defineProperty(exports, "SettingsToggleRow", {
16156
+ enumerable: true,
16157
+ get: function() {
16158
+ return SettingsToggleRow;
16159
+ }
16160
+ });
16173
16161
  Object.defineProperty(exports, "require_react_dom", {
16174
16162
  enumerable: true,
16175
16163
  get: function() {
16176
16164
  return require_react_dom;
16177
16165
  }
16178
16166
  });
16167
+ Object.defineProperty(exports, "settingsControlClass", {
16168
+ enumerable: true,
16169
+ get: function() {
16170
+ return settingsControlClass;
16171
+ }
16172
+ });
16173
+ Object.defineProperty(exports, "settingsIconButtonStyle", {
16174
+ enumerable: true,
16175
+ get: function() {
16176
+ return settingsIconButtonStyle;
16177
+ }
16178
+ });
16179
16179
  return module.exports;
16180
16180
  }
16181
16181
  });
@@ -16275,6 +16275,9 @@ window.__ModuleLoader__.load({
16275
16275
  "zh"
16276
16276
  ];
16277
16277
  const DEFAULT_SESSION_TRANSLATION_SETTINGS = {
16278
+ inputEnabled: true,
16279
+ reasoningEnabled: true,
16280
+ assistantEnabled: true,
16278
16281
  inputLanguage: "en",
16279
16282
  outputLanguage: "zh",
16280
16283
  bilingual: false,
@@ -16309,13 +16312,18 @@ window.__ModuleLoader__.load({
16309
16312
  if (value === void 0) return fallback;
16310
16313
  const translationModel = normalizeTranslationModel(value.translationModel);
16311
16314
  const translationModels = Array.isArray(value.translationModels) ? normalizeTranslationModels(value.translationModels) : void 0;
16315
+ const translationRules = Array.isArray(value.translationRules) ? value.translationRules.filter((rule) => typeof rule === "string").map((rule) => rule.trim()).filter((rule) => rule !== "") : void 0;
16312
16316
  return {
16317
+ inputEnabled: value.inputEnabled !== false,
16318
+ reasoningEnabled: value.reasoningEnabled !== false,
16319
+ assistantEnabled: value.assistantEnabled !== false,
16313
16320
  inputLanguage: isSessionTranslationLanguage(value.inputLanguage) ? value.inputLanguage : fallback.inputLanguage,
16314
16321
  outputLanguage: isSessionTranslationLanguage(value.outputLanguage) ? value.outputLanguage : fallback.outputLanguage,
16315
16322
  bilingual: value.bilingual === true,
16316
16323
  nativeEnabled: value.nativeEnabled === true,
16317
16324
  ...translationModel === void 0 ? {} : { translationModel },
16318
- ...translationModels === void 0 ? {} : { translationModels }
16325
+ ...translationModels === void 0 ? {} : { translationModels },
16326
+ ...translationRules === void 0 ? {} : { translationRules }
16319
16327
  };
16320
16328
  }
16321
16329
  function normalizeTranslationModels(values) {
@@ -18013,6 +18021,12 @@ window.__ModuleLoader__.load({
18013
18021
  "cli.adapterDisabled": "{name} disabled",
18014
18022
  "cli.translationConversation": "Translate conversation",
18015
18023
  "cli.translationConversationToggle": "Toggle conversation translation",
18024
+ "cli.translationSettings": "Conversation translation settings",
18025
+ "cli.translationSettingsClose": "Close",
18026
+ "cli.translationSettingsDescription": "Choose which messages to translate in conversations with translation enabled.",
18027
+ "cli.translationUserMessages": "Translate user messages",
18028
+ "cli.translationThinkingMessages": "Translate AI thinking messages",
18029
+ "cli.translationAssistantMessages": "Translate AI final messages",
18016
18030
  "lan.fieldListenPort": "listen port",
18017
18031
  "lan.fieldDshPort": "DSH local port",
18018
18032
  "lan.fieldMustBeNumber": "{field} must be a number",
@@ -18025,6 +18039,17 @@ window.__ModuleLoader__.load({
18025
18039
  "translation.outputTitle": "Translate the AI’s reasoning and final messages into the language specified below",
18026
18040
  "translation.outputLanguage": "Reply language",
18027
18041
  "translation.modelTitle": "Translation model pool",
18042
+ "translation.rulesTitle": "Translation rules",
18043
+ "translation.rulesHelp": "Rules apply to input, reasoning, and replies, including text already in the target language. They take priority over the default translation prompts.",
18044
+ "translation.rulesEmpty": "No custom rules. The default translation prompts apply.",
18045
+ "translation.ruleAdd": "Add rule",
18046
+ "translation.ruleEdit": "Edit rule {number}",
18047
+ "translation.ruleRemove": "Remove rule {number}",
18048
+ "translation.ruleText": "Rule instructions",
18049
+ "translation.rulePlaceholder": "For example: Keep product names in their original language.",
18050
+ "translation.ruleSave": "Save rule",
18051
+ "translation.ruleSaving": "Saving…",
18052
+ "translation.ruleCancel": "Cancel",
18028
18053
  "translation.modelFollowDefault": "Use the default DSH model",
18029
18054
  "translation.modelResetTitle": "Use the default DSH model?",
18030
18055
  "translation.modelResetHelp": "This will clear all {count} models and their priority order from the pool, then follow the default DSH model. Continue?",
@@ -18056,6 +18081,12 @@ window.__ModuleLoader__.load({
18056
18081
  "translation.statusTranslating": "Translating…",
18057
18082
  "translation.progressHelp": "Preparing and translating your message. The translation result will be available when this finishes.",
18058
18083
  "translation.statusFailed": "Translation failed; original kept",
18084
+ "translation.retry": "Retry translation",
18085
+ "translation.sendDirectly": "Send directly",
18086
+ "translation.cancelSending": "Cancel sending",
18087
+ "translation.inputFailedTitle": "Message translation failed",
18088
+ "translation.inputFailedHelp": "Your message has not been sent. Choose how to continue.",
18089
+ "translation.decisionFailed": "Could not apply your choice. Please try again.",
18059
18090
  "translation.statusNotNeeded": "Already in the target language; translation skipped",
18060
18091
  "translation.detectedLanguage": "Detected language",
18061
18092
  "translation.modelNotUsed": "Not used; translation was unnecessary",
@@ -18091,6 +18122,12 @@ window.__ModuleLoader__.load({
18091
18122
  "cli.adapterDisabled": "已停用 {name}",
18092
18123
  "cli.translationConversation": "翻译对话",
18093
18124
  "cli.translationConversationToggle": "切换对话翻译",
18125
+ "cli.translationSettings": "对话翻译设置",
18126
+ "cli.translationSettingsClose": "关闭",
18127
+ "cli.translationSettingsDescription": "选择已开启对话翻译的会话中需要翻译的消息类型。",
18128
+ "cli.translationUserMessages": "翻译用户消息",
18129
+ "cli.translationThinkingMessages": "翻译 AI 思考消息",
18130
+ "cli.translationAssistantMessages": "翻译 AI 正式消息",
18094
18131
  "lan.fieldListenPort": "监听端口",
18095
18132
  "lan.fieldDshPort": "DSH 本地端口",
18096
18133
  "lan.fieldMustBeNumber": "{field} 必须是数字",
@@ -18103,6 +18140,17 @@ window.__ModuleLoader__.load({
18103
18140
  "translation.outputTitle": "AI的思考内容和正式消息翻译为以下指定语言",
18104
18141
  "translation.outputLanguage": "回复语言",
18105
18142
  "translation.modelTitle": "翻译模型池",
18143
+ "translation.rulesTitle": "翻译规则",
18144
+ "translation.rulesHelp": "规则适用于输入、思考和回复,包括已经是目标语言的文本。规则的优先级高于默认翻译提示词。",
18145
+ "translation.rulesEmpty": "尚未添加自定义规则,使用默认翻译提示词。",
18146
+ "translation.ruleAdd": "添加规则",
18147
+ "translation.ruleEdit": "编辑规则 {number}",
18148
+ "translation.ruleRemove": "移除规则 {number}",
18149
+ "translation.ruleText": "规则内容",
18150
+ "translation.rulePlaceholder": "例如:产品名称保留原文,不进行翻译。",
18151
+ "translation.ruleSave": "保存规则",
18152
+ "translation.ruleSaving": "正在保存…",
18153
+ "translation.ruleCancel": "取消",
18106
18154
  "translation.modelFollowDefault": "跟随 DSH 默认模型",
18107
18155
  "translation.modelResetTitle": "确认跟随 DSH 默认模型?",
18108
18156
  "translation.modelResetHelp": "这将清空模型池中的全部 {count} 个模型及其优先级顺序,并改为跟随 DSH 默认模型。是否继续?",
@@ -18134,6 +18182,12 @@ window.__ModuleLoader__.load({
18134
18182
  "translation.statusTranslating": "正在翻译…",
18135
18183
  "translation.progressHelp": "正在准备并翻译消息,完成后可查看翻译结果。",
18136
18184
  "translation.statusFailed": "翻译失败,已保留原文",
18185
+ "translation.retry": "重试翻译",
18186
+ "translation.sendDirectly": "直接发送",
18187
+ "translation.cancelSending": "取消发送",
18188
+ "translation.inputFailedTitle": "消息翻译失败",
18189
+ "translation.inputFailedHelp": "消息尚未发送,请选择如何继续。",
18190
+ "translation.decisionFailed": "未能应用你的选择,请重试。",
18137
18191
  "translation.statusNotNeeded": "原文已是目标语言,无需翻译",
18138
18192
  "translation.detectedLanguage": "检测到的语言",
18139
18193
  "translation.modelNotUsed": "未调用,原文无需翻译",
@@ -20580,10 +20634,10 @@ window.__ModuleLoader__.load({
20580
20634
  const require_assistant_notifications = require("@jingyi0605/codingns4dsh/client.assistant-notifications.js");
20581
20635
  const require_session_translation = require("@jingyi0605/codingns4dsh/client.session-translation.js");
20582
20636
  const require_theme = require("@jingyi0605/codingns4dsh/client.theme.js");
20583
- const require_moss_voice_output = require("@jingyi0605/codingns4dsh/client.moss-voice-output.js");
20637
+ const require_react_dom$1 = require("@jingyi0605/codingns4dsh/client.react-dom.js");
20584
20638
  const require_manager = require("@jingyi0605/codingns4dsh/client.manager.js");
20585
20639
  const require_primitives_adapter = require("@jingyi0605/codingns4dsh/client.primitives-adapter.js");
20586
- const require_react_dom$1 = require("@jingyi0605/codingns4dsh/client.react-dom.js");
20640
+ const require_moss_voice_output = require("@jingyi0605/codingns4dsh/client.moss-voice-output.js");
20587
20641
  const require_assistant_voice_sessions = require("@jingyi0605/codingns4dsh/client.assistant-voice-sessions.js");
20588
20642
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
20589
20643
  _deepseek_ai_dsh_client_ui_primitives = require_rolldown_runtime.__toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
@@ -22180,7 +22234,7 @@ window.__ModuleLoader__.load({
22180
22234
  disabled: controlsDisabled || busy,
22181
22235
  onClick: () => void detect(),
22182
22236
  style: buttonStyle
22183
- }, t("lan.detect")))), detectedDshPorts.length > 1 && (0, react.createElement)("div", { style: require_theme.dshSettingsNoteStyle }, t("lan.detectMultiple", { ports: detectedDshPorts.join(t("common.listSeparator")) })), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
22237
+ }, t("lan.detect")))), detectedDshPorts.length > 1 && (0, react.createElement)("div", { style: require_theme.dshSettingsNoteStyle }, t("lan.detectMultiple", { ports: detectedDshPorts.join(t("common.listSeparator")) })), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
22184
22238
  label: t("lan.autoStart"),
22185
22239
  checked: autoStart,
22186
22240
  disabled: controlsDisabled || busy,
@@ -23994,15 +24048,15 @@ window.__ModuleLoader__.load({
23994
24048
  sendHello() {
23995
24049
  this.send(this.createEnvelope("session.hello", "session", {
23996
24050
  protocol: this.options.protocol ?? "dsh-transport-v1",
23997
- dshVersion: this.options.dshVersion ?? "0.2.1-alpha.2",
24051
+ dshVersion: this.options.dshVersion ?? "0.2.1-alpha.3",
23998
24052
  capabilities: [...this.options.capabilities ?? []]
23999
24053
  }));
24000
24054
  }
24001
24055
  sendReady(capabilities, peerDshVersion) {
24002
24056
  this.send(this.createEnvelope("session.ready", "session", {
24003
24057
  protocol: this.options.protocol ?? "dsh-transport-v1",
24004
- dshVersion: peerDshVersion ?? this.options.dshVersion ?? "0.2.1-alpha.2",
24005
- hostDshVersion: this.options.dshVersion ?? "0.2.1-alpha.2",
24058
+ dshVersion: peerDshVersion ?? this.options.dshVersion ?? "0.2.1-alpha.3",
24059
+ hostDshVersion: this.options.dshVersion ?? "0.2.1-alpha.3",
24006
24060
  capabilities: [...capabilities],
24007
24061
  byteCredit: 65536,
24008
24062
  messageCredit: 32
@@ -27035,7 +27089,7 @@ window.__ModuleLoader__.load({
27035
27089
  color: require_theme.dshThemeColor.labelSecondary,
27036
27090
  fontSize: require_theme.uiFontSize(13),
27037
27091
  lineHeight: 1.5
27038
- } }, t("loginProtection.panelHint")), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
27092
+ } }, t("loginProtection.panelHint")), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
27039
27093
  label: t("loginProtection.enable"),
27040
27094
  checked: active,
27041
27095
  disabled: controlsDisabled || busy,
@@ -27092,7 +27146,7 @@ window.__ModuleLoader__.load({
27092
27146
  "relay",
27093
27147
  t("loginProtection.scopeRelay"),
27094
27148
  t("loginProtection.scopeRelayHint")
27095
- ]].map(([key, label, hint]) => (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
27149
+ ]].map(([key, label, hint]) => (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
27096
27150
  key,
27097
27151
  label: t("loginProtection.scopeOption", {
27098
27152
  label,
@@ -28205,7 +28259,7 @@ window.__ModuleLoader__.load({
28205
28259
  if (slots === void 0) return;
28206
28260
  context.resources.add(registerExternalToolStreamUi(context.services));
28207
28261
  const { registerCliConversationSlots } = await Promise.resolve().then(() => cli_slots_exports);
28208
- const disposeSlots = registerCliConversationSlots(slots, context.services.rpc, context.services.locale, readNativeTranslationDefault);
28262
+ const disposeSlots = registerCliConversationSlots(slots, context.services.rpc, context.services.locale, readNativeTranslationDefault, context.services.settings);
28209
28263
  context.resources.add(disposeSlots);
28210
28264
  },
28211
28265
  settingsPanel: CliAdaptersPanel
@@ -28495,7 +28549,7 @@ window.__ModuleLoader__.load({
28495
28549
  marginTop: 3,
28496
28550
  ...require_theme.dshSettingsHelpStyle,
28497
28551
  opacity: .75
28498
- } }, t("cli.subagentBridgeDescription"))), (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
28552
+ } }, t("cli.subagentBridgeDescription"))), (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
28499
28553
  "aria-label": t("cli.subagentBridgeToggle"),
28500
28554
  checked: bridgeEnabled,
28501
28555
  disabled: !bridgeWritable || bridgeBusy,
@@ -28637,7 +28691,7 @@ window.__ModuleLoader__.load({
28637
28691
  gap: 6,
28638
28692
  flex: "0 0 auto"
28639
28693
  }
28640
- }, (0, react.createElement)("span", { "aria-hidden": true }, adapter.enabled ? t("cli.enabled") : t("cli.disabled")), (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
28694
+ }, (0, react.createElement)("span", { "aria-hidden": true }, adapter.enabled ? t("cli.enabled") : t("cli.disabled")), (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
28641
28695
  "aria-label": t("cli.adapterToggle", { name: adapter.name }),
28642
28696
  checked: adapter.enabled,
28643
28697
  disabled: peerHostId !== null || !adapter.installed || busyAdapterId === adapter.id,
@@ -28955,7 +29009,7 @@ window.__ModuleLoader__.load({
28955
29009
  gap: 12,
28956
29010
  minHeight: 36,
28957
29011
  width: "100%"
28958
- } }, (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, appearance.cursorBlink ? t("terminal.cursorOn") : t("terminal.cursorOff")), (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
29012
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsHelpStyle }, appearance.cursorBlink ? t("terminal.cursorOn") : t("terminal.cursorOff")), (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
28959
29013
  "aria-label": t("terminal.cursorBlink"),
28960
29014
  checked: appearance.cursorBlink,
28961
29015
  disabled,
@@ -30767,31 +30821,31 @@ window.__ModuleLoader__.load({
30767
30821
  opacity: disabled ? .5 : 1,
30768
30822
  pointerEvents: disabled ? "none" : "auto"
30769
30823
  }
30770
- }, (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30824
+ }, (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30771
30825
  label: t("workspace.optimizeSessionTitles"),
30772
30826
  description: t("workspace.optimizeSessionTitlesDescription"),
30773
30827
  checked: value.optimizeSessionTitles ?? require_native_workspace_store.DEFAULT_WORKSPACE_SESSION_ENHANCEMENT_SETTINGS.optimizeSessionTitles,
30774
30828
  disabled,
30775
30829
  onChange: (checked) => updateSetting("optimizeSessionTitles", checked)
30776
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30830
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30777
30831
  label: t("workspace.showLogo"),
30778
30832
  description: t("workspace.logoDescription"),
30779
30833
  checked: value.showAdapterLogo,
30780
30834
  disabled,
30781
30835
  onChange: (checked) => updateSetting("showAdapterLogo", checked)
30782
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30836
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30783
30837
  label: t("workspace.showSkillQuickReference"),
30784
30838
  description: t("workspace.skillQuickReferenceDescription"),
30785
30839
  checked: value.showSkillQuickReference,
30786
30840
  disabled,
30787
30841
  onChange: (checked) => updateSetting("showSkillQuickReference", checked)
30788
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30842
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30789
30843
  label: t("workspace.showWorkspaceHiding"),
30790
30844
  description: t("workspace.workspaceHidingDescription"),
30791
30845
  checked: value.showWorkspaceHiding,
30792
30846
  disabled,
30793
30847
  onChange: (checked) => updateSetting("showWorkspaceHiding", checked)
30794
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30848
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30795
30849
  label: t("workspace.showSubscriptionUsage"),
30796
30850
  description: t("workspace.subscriptionUsageDescription"),
30797
30851
  checked: value.showSubscriptionUsage,
@@ -30799,28 +30853,28 @@ window.__ModuleLoader__.load({
30799
30853
  onChange: (checked) => updateSetting("showSubscriptionUsage", checked),
30800
30854
  actions: (0, react.createElement)("button", {
30801
30855
  type: "button",
30802
- className: require_moss_voice_output.settingsControlClass.iconButton,
30856
+ className: require_react_dom$1.settingsControlClass.iconButton,
30803
30857
  "aria-haspopup": "dialog",
30804
30858
  "aria-expanded": usageSettingsOpen,
30805
30859
  "aria-label": t("workspace.subscriptionUsageSettings"),
30806
30860
  title: t("workspace.subscriptionUsageSettings"),
30807
30861
  disabled,
30808
30862
  onClick: () => setUsageSettingsOpen(true),
30809
- style: require_moss_voice_output.settingsIconButtonStyle
30863
+ style: require_react_dom$1.settingsIconButtonStyle
30810
30864
  }, createUsageSettingsGearIcon())
30811
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30865
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30812
30866
  label: t("workspace.showArchivedSessions"),
30813
30867
  description: t("workspace.archivedSessionsDescription"),
30814
30868
  checked: value.showArchivedSessions,
30815
30869
  disabled,
30816
30870
  onChange: (checked) => updateSetting("showArchivedSessions", checked)
30817
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30871
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30818
30872
  label: t("workspace.showQuickPhrases"),
30819
30873
  description: t("workspace.quickPhrasesDescription"),
30820
30874
  checked: value.showQuickPhrases,
30821
30875
  disabled,
30822
30876
  onChange: (checked) => updateSetting("showQuickPhrases", checked)
30823
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
30877
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
30824
30878
  label: t("workspace.rememberConversationRightbarRatio"),
30825
30879
  description: t("workspace.rememberConversationRightbarRatioDescription"),
30826
30880
  checked: value.rememberConversationRightbarRatio,
@@ -33455,6 +33509,61 @@ window.__ModuleLoader__.load({
33455
33509
  };
33456
33510
  }
33457
33511
  //#endregion
33512
+ //#region src/client/conversation-translation-settings.ts
33513
+ const messageSettings = [
33514
+ ["inputEnabled", "cli.translationUserMessages"],
33515
+ ["reasoningEnabled", "cli.translationThinkingMessages"],
33516
+ ["assistantEnabled", "cli.translationAssistantMessages"]
33517
+ ];
33518
+ /** Shared message preferences, independent of each conversation's master switch. */
33519
+ function ConversationTranslationSettings(props) {
33520
+ const { settings, t } = props;
33521
+ const snapshot = (0, react.useSyncExternalStore)(settings.subscribe.bind(settings), settings.getSnapshot.bind(settings), settings.getSnapshot.bind(settings));
33522
+ const [saving, setSaving] = (0, react.useState)(false);
33523
+ const savingRef = (0, react.useRef)(false);
33524
+ const [error, setError] = (0, react.useState)(null);
33525
+ const disabled = snapshot.status !== "ready" || !snapshot.writable || saving;
33526
+ const save = async (field, checked) => {
33527
+ if (disabled || savingRef.current) return;
33528
+ savingRef.current = true;
33529
+ setSaving(true);
33530
+ setError(null);
33531
+ try {
33532
+ if (!await settings.mutate([{
33533
+ op: "set",
33534
+ path: ["sessionTranslation", field],
33535
+ value: checked
33536
+ }])) throw new Error(t("translation.saveRejected"));
33537
+ } catch (cause) {
33538
+ setError(cause instanceof Error ? cause.message : String(cause));
33539
+ } finally {
33540
+ savingRef.current = false;
33541
+ setSaving(false);
33542
+ }
33543
+ };
33544
+ return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
33545
+ open: true,
33546
+ title: t("cli.translationSettings"),
33547
+ description: t("cli.translationSettingsDescription"),
33548
+ closeLabel: t("cli.translationSettingsClose"),
33549
+ onClose: props.onClose
33550
+ }, ...messageSettings.map(([field, label]) => (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
33551
+ key: field,
33552
+ label: t(label),
33553
+ checked: snapshot.value?.sessionTranslation?.[field] !== false,
33554
+ disabled,
33555
+ onChange: (checked) => {
33556
+ save(field, checked);
33557
+ }
33558
+ })), error === null ? null : (0, react.createElement)("div", {
33559
+ role: "alert",
33560
+ style: {
33561
+ color: require_theme.dshThemeColor.error,
33562
+ marginTop: 8
33563
+ }
33564
+ }, error));
33565
+ }
33566
+ //#endregion
33458
33567
  //#region src/client/cli-slots.ts
33459
33568
  var cli_slots_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
33460
33569
  AgentSlot: () => AgentSlot,
@@ -33598,7 +33707,7 @@ window.__ModuleLoader__.load({
33598
33707
  * `readNativeTranslationEnabled` 提供「DSH 原生会话未单独设置翻译开关时是否跟随总开关」
33599
33708
  * 的当前值;原生会话的翻译开关与外部 Agent 共用模型菜单里的同一行开关。
33600
33709
  */
33601
- function registerCliConversationSlots(slots, rpc, locale, readNativeTranslationEnabled) {
33710
+ function registerCliConversationSlots(slots, rpc, locale, readNativeTranslationEnabled, settings) {
33602
33711
  installComposerStyles();
33603
33712
  const t = locale.bind("codingns");
33604
33713
  const disposeAgent = slots.inject("conversation.input.right", () => slots.register({
@@ -33621,6 +33730,7 @@ window.__ModuleLoader__.load({
33621
33730
  rpc,
33622
33731
  sessionId,
33623
33732
  locale,
33733
+ settings,
33624
33734
  ...readNativeTranslationEnabled === void 0 ? {} : { readNativeTranslationEnabled }
33625
33735
  })
33626
33736
  }, ModelSlot));
@@ -33739,7 +33849,23 @@ window.__ModuleLoader__.load({
33739
33849
  return (0, react.createElement)("div", {
33740
33850
  className: "codingns4dsh-translation-toggle",
33741
33851
  style: serviceTierRowStyle
33742
- }, (0, react.createElement)("span", { style: serviceTierLabelStyle }, props.label), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
33852
+ }, (0, react.createElement)("span", { style: {
33853
+ ...serviceTierLabelStyle,
33854
+ flex: "1 1 auto",
33855
+ whiteSpace: "normal"
33856
+ } }, props.label), (0, react.createElement)("button", {
33857
+ type: "button",
33858
+ "aria-label": props.settingsLabel,
33859
+ title: props.settingsLabel,
33860
+ "aria-haspopup": "dialog",
33861
+ onClick: props.onSettings,
33862
+ style: {
33863
+ ...require_react_dom$1.settingsIconButtonStyle,
33864
+ flexBasis: 24,
33865
+ width: 24,
33866
+ height: 28
33867
+ }
33868
+ }, (0, react.createElement)(require_primitives_adapter.resolveAssistantControlIcon("settings"), { size: 16 })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
33743
33869
  checked: props.checked,
33744
33870
  onChange: props.onChange,
33745
33871
  label: props.toggleLabel
@@ -33933,6 +34059,7 @@ window.__ModuleLoader__.load({
33933
34059
  const [catalogRetry, setCatalogRetry] = (0, react.useState)(0);
33934
34060
  const [open, setOpen] = (0, react.useState)(false);
33935
34061
  const [pane, setPane] = (0, react.useState)("root");
34062
+ const [translationSettingsOpen, setTranslationSettingsOpen] = (0, react.useState)(false);
33936
34063
  const rootRef = (0, react.useRef)(null);
33937
34064
  useDismissOnOutsidePointer(rootRef, open, () => {
33938
34065
  setOpen(false);
@@ -34021,6 +34148,15 @@ window.__ModuleLoader__.load({
34021
34148
  (0, react.useEffect)(() => {
34022
34149
  if (selection.adapterId === "dsh") setOpen(false);
34023
34150
  }, [selection.adapterId]);
34151
+ const translationSettings = translationSettingsOpen && props.settings !== void 0 ? (0, react.createElement)(ConversationTranslationSettings, {
34152
+ settings: props.settings,
34153
+ t,
34154
+ onClose: () => setTranslationSettingsOpen(false)
34155
+ }) : null;
34156
+ const openTranslationSettings = () => {
34157
+ setOpen(false);
34158
+ setTranslationSettingsOpen(true);
34159
+ };
34024
34160
  if (selection.adapterId === "dsh") return (0, react.createElement)("div", {
34025
34161
  ref: rootRef,
34026
34162
  hidden: true
@@ -34031,8 +34167,10 @@ window.__ModuleLoader__.load({
34031
34167
  onChange: (next) => update({
34032
34168
  ...selection,
34033
34169
  translationEnabled: next
34034
- })
34035
- }), nativeMenu) : null);
34170
+ }),
34171
+ settingsLabel: t("cli.translationSettings"),
34172
+ onSettings: openTranslationSettings
34173
+ }), nativeMenu) : null, translationSettings);
34036
34174
  const model = catalog === null ? void 0 : require_model_catalog_cache.findModel(catalog, selection.modelId) ?? require_model_catalog_cache.firstModel(catalog);
34037
34175
  const efforts = model?.efforts ?? [];
34038
34176
  const storedEffort = selection.effortId;
@@ -34108,7 +34246,9 @@ window.__ModuleLoader__.load({
34108
34246
  checked: selection.translationEnabled === true,
34109
34247
  label: t("cli.translationConversation"),
34110
34248
  toggleLabel: t("cli.translationConversationToggle"),
34111
- onChange: toggleTranslation
34249
+ onChange: toggleTranslation,
34250
+ settingsLabel: t("cli.translationSettings"),
34251
+ onSettings: openTranslationSettings
34112
34252
  })] : [],
34113
34253
  ...serviceTierAvailable ? [(0, react.createElement)("div", {
34114
34254
  key: "service-tier",
@@ -34229,7 +34369,7 @@ window.__ModuleLoader__.load({
34229
34369
  role: "menu",
34230
34370
  "aria-label": t("cli.chooseModelMenu"),
34231
34371
  style: nativeMenuStyle
34232
- }, ...menu));
34372
+ }, ...menu), translationSettings);
34233
34373
  }
34234
34374
  function effortDisplayName(model, effort, defaultLabel) {
34235
34375
  if (effort === "default") return defaultLabel;
@@ -36360,7 +36500,7 @@ ${scope} [data-dockkit-strip-tabs] {
36360
36500
  display: "block",
36361
36501
  marginTop: 3,
36362
36502
  ...require_theme.dshSettingsHelpStyle
36363
- } }, t("mobile.hideSidebarOnMobileDescription"))), (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
36503
+ } }, t("mobile.hideSidebarOnMobileDescription"))), (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
36364
36504
  "aria-label": t("mobile.hideSidebarOnMobile"),
36365
36505
  checked: value.hideSidebarOnMobile,
36366
36506
  disabled: controlsDisabled,
@@ -36373,7 +36513,7 @@ ${scope} [data-dockkit-strip-tabs] {
36373
36513
  display: "block",
36374
36514
  marginTop: 3,
36375
36515
  ...require_theme.dshSettingsHelpStyle
36376
- } }, t("mobile.optimizeSettingsOnMobileDescription"))), (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
36516
+ } }, t("mobile.optimizeSettingsOnMobileDescription"))), (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
36377
36517
  "aria-label": t("mobile.optimizeSettingsOnMobile"),
36378
36518
  checked: value.optimizeSettingsOnMobile,
36379
36519
  disabled: controlsDisabled,
@@ -36415,7 +36555,7 @@ ${scope} [data-dockkit-strip-tabs] {
36415
36555
  display: "block",
36416
36556
  marginTop: 3,
36417
36557
  ...require_theme.dshSettingsHelpStyle
36418
- } }, t("mobile.sidebarGesturesDescription"))), (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
36558
+ } }, t("mobile.sidebarGesturesDescription"))), (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
36419
36559
  "aria-label": t("mobile.sidebarGestures"),
36420
36560
  checked: gestures.sidebarGestures,
36421
36561
  disabled: controlsDisabled,
@@ -36475,20 +36615,20 @@ ${scope} [data-dockkit-strip-tabs] {
36475
36615
  } }, t("lan.pwa.description")), (0, react.createElement)("p", { style: {
36476
36616
  margin: 0,
36477
36617
  ...require_theme.dshSettingsHelpStyle
36478
- } }, t("mobile.pwaRequiresListener")), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
36618
+ } }, t("mobile.pwaRequiresListener")), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
36479
36619
  label: t("lan.pwa.enabled"),
36480
36620
  description: t("lan.pwa.enabledHelp"),
36481
36621
  checked: pwa.enabled,
36482
36622
  disabled: controlsDisabled,
36483
36623
  onChange: (checked) => updatePwa({ enabled: checked })
36484
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
36624
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
36485
36625
  label: t("lan.pwa.serviceWorker"),
36486
36626
  description: t("lan.pwa.serviceWorkerHelp"),
36487
36627
  checked: pwa.serviceWorker,
36488
36628
  disabled: controlsDisabled || !pwa.enabled,
36489
36629
  style: { opacity: pwa.enabled ? 1 : .55 },
36490
36630
  onChange: (checked) => updatePwa({ serviceWorker: checked })
36491
- }), (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
36631
+ }), (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
36492
36632
  label: t("lan.pwa.installPrompt"),
36493
36633
  checked: pwa.installPrompt,
36494
36634
  disabled: controlsDisabled || !pwa.enabled,
@@ -41104,7 +41244,7 @@ ${scope} [data-dockkit-strip-tabs] {
41104
41244
  }, createSwitchRow(t("fileManagement.menuEnhancement"), t("fileManagement.menuEnhancementDescription"), value.menuEnhancement, disabled, (next) => updateSetting("menuEnhancement", next)), createSwitchRow(t("fileManagement.fileEditor"), t("fileManagement.fileEditorDescription"), value.fileEditor, disabled, (next) => updateSetting("fileEditor", next)), createSwitchRow(t("fileManagement.sessionChangedFiles"), t("fileManagement.sessionChangedFilesDescription"), value.sessionChangedFiles, disabled, (next) => updateSetting("sessionChangedFiles", next)));
41105
41245
  }
41106
41246
  function createSwitchRow(label, description, checked, disabled, onChange) {
41107
- return (0, react.createElement)(require_moss_voice_output.SettingsToggleRow, {
41247
+ return (0, react.createElement)(require_react_dom$1.SettingsToggleRow, {
41108
41248
  label,
41109
41249
  description,
41110
41250
  checked,
@@ -52643,1177 +52783,357 @@ ${scope} [data-dockkit-strip-tabs] {
52643
52783
  @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}}
52644
52784
  `;
52645
52785
  //#endregion
52646
- //#region src/shared/translation-indicator.ts
52647
- const TRANSLATION_GLYPH_PATHS = ["M3.5 5.5h10M8.5 3.5v2M12.5 5.5c0 4.4-3.3 7.2-8 9", "M5.5 8.5c1.4 2 3.4 3.7 6 4.8M14.5 19.5l3-8 3 8M15.7 17h3.6"];
52648
- const TRANSLATION_STATUS_BADGE_STYLE = {
52649
- position: "absolute",
52650
- top: "1px",
52651
- right: "1px",
52652
- display: "grid",
52653
- placeItems: "center",
52654
- width: "10px",
52655
- height: "10px",
52656
- zIndex: "1",
52657
- boxSizing: "border-box",
52658
- border: "1.5px solid var(--dsw-alias-bg-base, Canvas)",
52659
- borderRadius: "50%",
52660
- color: "#fff",
52661
- fontSize: "6px",
52662
- fontWeight: "700",
52663
- lineHeight: "1"
52664
- };
52665
- const TRANSLATION_PENDING_BADGE_STYLE = {
52666
- border: "1.5px solid var(--dsw-alias-button-info-fill, #1677ff)",
52667
- borderTopColor: "transparent",
52668
- background: "transparent"
52669
- };
52670
- //#endregion
52671
- //#region src/client/session-translation-pending-dom.ts
52672
- /** Pending DSH bubbles have no renderer slot; attach only to their action rows. */
52673
- function watchPendingTranslationTargets(anchor, onChange) {
52674
- const root = anchor.closest("[data-conversation-session]");
52675
- const Observer = anchor.ownerDocument.defaultView?.MutationObserver;
52676
- if (root === null || Observer === void 0) return () => void 0;
52677
- const targets = /* @__PURE__ */ new Map();
52678
- let nextKey = 0;
52679
- const scan = () => {
52680
- observer.disconnect();
52681
- let changed = false;
52682
- const rows = new Set(root.querySelectorAll("[data-submission-echo]"));
52683
- for (const [row, target] of targets) {
52684
- if (rows.has(row) && root.contains(target.container)) continue;
52685
- target.container.remove();
52686
- targets.delete(row);
52687
- changed = true;
52688
- }
52689
- for (const row of rows) {
52690
- if (row.closest("[data-conversation-session]") !== root) continue;
52691
- const original = row.querySelector("[class*=\"bubble\"]")?.textContent ?? "";
52692
- const actions = row.querySelector("[data-clock=\"start\"]");
52693
- if (original.trim() === "" || actions === null) continue;
52694
- const existing = targets.get(row);
52695
- if (existing !== void 0) {
52696
- if (existing.original !== original) {
52697
- targets.set(row, {
52698
- ...existing,
52699
- original
52700
- });
52701
- changed = true;
52702
- }
52703
- continue;
52704
- }
52705
- const container = anchor.ownerDocument.createElement("span");
52706
- container.dataset.codingnsPendingTranslation = "";
52707
- container.style.display = "inline-flex";
52708
- let before = actions.querySelector("button");
52709
- while (before !== null && before.parentElement !== actions) before = before.parentElement;
52710
- actions.insertBefore(container, before);
52711
- targets.set(row, {
52712
- key: nextKey++,
52713
- container,
52714
- original
52715
- });
52716
- changed = true;
52717
- }
52718
- if (changed) onChange([...targets.values()]);
52719
- observer.observe(root, {
52720
- childList: true,
52721
- subtree: true,
52722
- characterData: true
52723
- });
52786
+ //#region src/client/session-translation-rules.ts
52787
+ /** Only saved entries enter translation prompts; cancelled or failed edits stay local. */
52788
+ function SessionTranslationRules({ rules, disabled, pending, t, onChange }) {
52789
+ const [draft, setDraft] = (0, react.useState)(null);
52790
+ const [saveFailed, setSaveFailed] = (0, react.useState)(false);
52791
+ const identity = JSON.stringify(rules);
52792
+ (0, react.useEffect)(() => {
52793
+ setDraft(null);
52794
+ }, [identity]);
52795
+ (0, react.useEffect)(() => {
52796
+ if (disabled && !pending) setDraft(null);
52797
+ }, [disabled, pending]);
52798
+ const close = () => {
52799
+ if (!pending) setDraft(null);
52724
52800
  };
52725
- const observer = new Observer(scan);
52726
- scan();
52727
- return () => {
52728
- observer.disconnect();
52729
- for (const target of targets.values()) target.container.remove();
52730
- targets.clear();
52801
+ const edit = (index) => {
52802
+ if (disabled || draft !== null) return;
52803
+ setSaveFailed(false);
52804
+ setDraft({
52805
+ index,
52806
+ text: rules[index] ?? ""
52807
+ });
52731
52808
  };
52732
- }
52733
- //#endregion
52734
- //#region src/client/session-translation-chat.ts
52735
- /**
52736
- * 把翻译状态和查看原文的入口放回对应消息块,不占用 AI 回复底部的统一操作栏。
52737
- */
52738
- function TranslationAction(props) {
52739
- const [open, setOpen] = (0, react.useState)(false);
52740
- const rootRef = (0, react.useRef)(null);
52741
- const buttonRef = (0, react.useRef)(null);
52742
- const popupRef = (0, react.useRef)(null);
52743
- const [popupPosition, setPopupPosition] = (0, react.useState)(null);
52744
- useDismissOnOutsidePointer(rootRef, open, () => setOpen(false), { portal: popupRef });
52745
- (0, react.useLayoutEffect)(() => {
52746
- if (!open || typeof window === "undefined") {
52747
- setPopupPosition(null);
52809
+ const save = async () => {
52810
+ if (disabled || draft === null || draft.text.trim() === "") return;
52811
+ const next = [...rules];
52812
+ next[draft.index] = draft.text.trim();
52813
+ if (JSON.stringify(next) === identity) {
52814
+ close();
52748
52815
  return;
52749
52816
  }
52750
- const updatePosition = () => {
52751
- const button = buttonRef.current;
52752
- if (button === null) return;
52753
- const rect = button.getBoundingClientRect();
52754
- const edge = 12;
52755
- const gap = 8;
52756
- const width = Math.max(1, Math.min(420, window.innerWidth - 24));
52757
- const availableAbove = Math.max(0, rect.top - gap - edge);
52758
- const availableBelow = Math.max(0, window.innerHeight - rect.bottom - gap - edge);
52759
- const preferredHeight = Math.min(440, window.innerHeight * .65);
52760
- const placement = availableAbove >= preferredHeight || availableBelow < preferredHeight && availableAbove > availableBelow ? "above" : "below";
52761
- const maxHeight = Math.min(preferredHeight, placement === "above" ? availableAbove : availableBelow);
52762
- const desiredLeft = props.popupAlign === "end" ? rect.right - width : rect.left;
52763
- const maxLeft = Math.max(edge, window.innerWidth - edge - width);
52764
- setPopupPosition({
52765
- left: Math.min(maxLeft, Math.max(edge, desiredLeft)),
52766
- top: placement === "above" ? rect.top - gap : rect.bottom + gap,
52767
- width,
52768
- maxHeight,
52769
- placement
52770
- });
52771
- };
52772
- updatePosition();
52773
- window.addEventListener("resize", updatePosition);
52774
- window.addEventListener("scroll", updatePosition, true);
52775
- return () => {
52776
- window.removeEventListener("resize", updatePosition);
52777
- window.removeEventListener("scroll", updatePosition, true);
52778
- };
52779
- }, [open, props.popupAlign]);
52780
- const record = props.record;
52781
- const pending = record === void 0;
52782
- const failed = record?.failed === true;
52783
- const alreadyTargetLanguage = record?.alreadyTargetLanguage === true;
52784
- const statusText = pending ? props.translationT("translation.statusTranslating") : failed ? props.translationT("translation.statusFailed") : alreadyTargetLanguage ? props.translationT("translation.statusNotNeeded") : props.translationT("translation.statusTranslated");
52785
- const statusColor = pending ? require_theme.dshThemeColor.accent : failed ? require_theme.dshThemeColor.error : alreadyTargetLanguage ? require_theme.dshThemeColor.accent : require_theme.dshThemeColor.success;
52786
- const detailsId = `codingns-translation-details-${safeDomId(props.messageId)}`;
52787
- const details = open && popupPosition !== null ? (0, react.createElement)("div", {
52788
- ref: popupRef,
52789
- role: "dialog",
52790
- "aria-label": props.translationT("translation.detailsTitle"),
52791
- id: detailsId,
52817
+ setSaveFailed(false);
52818
+ if (await onChange(next)) setDraft(null);
52819
+ else setSaveFailed(true);
52820
+ };
52821
+ return (0, react.createElement)("div", {
52822
+ "aria-busy": pending,
52792
52823
  style: {
52793
- position: "fixed",
52794
- zIndex: 2147483647,
52795
- left: popupPosition.left,
52796
- top: popupPosition.top,
52797
- width: popupPosition.width,
52798
- maxHeight: popupPosition.maxHeight,
52799
- boxSizing: "border-box",
52800
- ...popupPosition.placement === "above" ? { transform: "translateY(-100%)" } : {},
52801
- overflow: "auto",
52802
- padding: "10px 12px",
52803
- border: `1px solid ${require_theme.dshThemeColor.border}`,
52804
- borderRadius: 8,
52805
- color: require_theme.dshThemeColor.labelPrimary,
52806
- background: require_theme.dshThemeColor.menuBackground,
52807
- boxShadow: "0 8px 24px color-mix(in srgb, CanvasText 16%, transparent)",
52808
- fontSize: require_theme.uiFontSize(12),
52809
- lineHeight: 1.45
52824
+ display: "grid",
52825
+ gap: 10,
52826
+ minWidth: 0
52810
52827
  }
52811
- }, (0, react.createElement)("div", { style: {
52812
- display: "flex",
52813
- justifyContent: "space-between",
52814
- gap: 10,
52815
- fontWeight: 600
52816
- } }, (0, react.createElement)("span", void 0, props.translationT("translation.detailsTitle")), (0, react.createElement)("span", {
52817
- role: "status",
52818
- "aria-live": "polite",
52828
+ }, (0, react.createElement)("div", { style: require_theme.dshSettingsHelpStyle }, t("translation.rulesHelp")), rules.length === 0 ? (0, react.createElement)("div", { style: require_theme.dshSettingsHelpStyle }, t("translation.rulesEmpty")) : (0, react.createElement)("ol", {
52829
+ "aria-label": t("translation.rulesTitle"),
52819
52830
  style: {
52820
- color: statusColor,
52821
- fontWeight: 400
52831
+ margin: 0,
52832
+ padding: 0,
52833
+ listStyle: "none"
52822
52834
  }
52823
- }, statusText)), record?.sourceLanguage === void 0 ? null : (0, react.createElement)("div", { style: {
52824
- marginTop: 8,
52825
- color: require_theme.dshThemeColor.labelSecondary
52826
- } }, `${props.translationT("translation.detectedLanguage")}: ${props.translationT(`translation.language.${record.sourceLanguage}`)}`), (0, react.createElement)(DetailBlock, {
52827
- kind: "original",
52828
- translationT: props.translationT,
52829
- value: record?.original ?? props.original ?? ""
52830
- }), pending ? (0, react.createElement)("progress", {
52831
- "aria-label": statusText,
52835
+ }, ...rules.map((rule, index) => (0, react.createElement)("li", {
52836
+ key: index,
52832
52837
  style: {
52833
- display: "block",
52834
- width: "100%",
52835
- height: 4,
52836
- marginTop: 8,
52837
- accentColor: require_theme.dshThemeColor.accent
52838
+ ...require_theme.dshSettingsListRowStyle,
52839
+ flexDirection: "column",
52840
+ alignItems: "stretch",
52841
+ gap: 6
52838
52842
  }
52839
- }) : null, pending ? (0, react.createElement)("div", {
52840
- role: "status",
52841
- "aria-live": "polite",
52842
- style: {
52843
- marginTop: 8,
52844
- color: require_theme.dshThemeColor.labelSecondary
52843
+ }, (0, react.createElement)("div", { style: {
52844
+ whiteSpace: "pre-wrap",
52845
+ overflowWrap: "anywhere"
52846
+ } }, rule), (0, react.createElement)("div", { style: {
52847
+ display: "flex",
52848
+ gap: 8,
52849
+ flexWrap: "wrap"
52850
+ } }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
52851
+ type: "button",
52852
+ size: "sm",
52853
+ variant: "outline",
52854
+ disabled: disabled || draft !== null,
52855
+ onClick: () => edit(index)
52856
+ }, t("translation.ruleEdit", { number: index + 1 })), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
52857
+ type: "button",
52858
+ size: "sm",
52859
+ disabled: disabled || draft !== null,
52860
+ onClick: () => {
52861
+ if (!disabled && draft === null) onChange(rules.filter((_, position) => position !== index));
52845
52862
  }
52846
- }, props.translationT("translation.progressHelp")) : (0, react.createElement)(DetailBlock, {
52847
- kind: props.messageRole === "user" ? "sent" : "translated",
52848
- translationT: props.translationT,
52849
- value: record.translated
52850
- }), pending ? null : (0, react.createElement)("div", { style: {
52851
- marginTop: 8,
52852
- color: require_theme.dshThemeColor.labelSecondary
52853
- } }, [
52854
- `${props.translationT("translation.modelUsed")}: ${alreadyTargetLanguage ? props.translationT("translation.modelNotUsed") : formatModel(record.model, props.translationT)}`,
52855
- ...record.durationMs === void 0 ? [] : [`${(record.durationMs / 1e3).toFixed(2)} s`],
52856
- ...record.totalTokens === void 0 ? [] : [`${record.totalTokens} tok`]
52857
- ].join(" · "))) : null;
52858
- const renderedDetails = details === null ? null : typeof document === "undefined" ? details : (0, import_react_dom.createPortal)(details, document.body);
52859
- return (0, react.createElement)("div", {
52860
- ref: rootRef,
52863
+ }, t("translation.ruleRemove", { number: index + 1 })))))), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
52864
+ type: "button",
52865
+ size: "sm",
52866
+ variant: "outline",
52867
+ disabled: disabled || draft !== null,
52868
+ style: { justifySelf: "start" },
52869
+ onClick: () => edit(rules.length)
52870
+ }, t("translation.ruleAdd")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
52871
+ open: draft !== null,
52872
+ onClose: close,
52873
+ title: t(draft?.index === rules.length ? "translation.ruleAdd" : "translation.ruleEdit", { number: (draft?.index ?? 0) + 1 }),
52874
+ closeLabel: t("translation.ruleCancel"),
52875
+ footer: (0, react.createElement)(react.Fragment, null, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
52876
+ type: "button",
52877
+ variant: "outline",
52878
+ disabled: pending,
52879
+ onClick: close
52880
+ }, t("translation.ruleCancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
52881
+ type: "button",
52882
+ variant: "primary",
52883
+ disabled: disabled || !draft?.text.trim(),
52884
+ onClick: () => {
52885
+ save();
52886
+ }
52887
+ }, t(pending ? "translation.ruleSaving" : "translation.ruleSave")))
52888
+ }, (0, react.createElement)("label", { style: {
52889
+ display: "grid",
52890
+ gap: 6
52891
+ } }, (0, react.createElement)("span", null, t("translation.ruleText")), (0, react.createElement)("textarea", {
52892
+ rows: 5,
52893
+ value: draft?.text ?? "",
52894
+ disabled,
52895
+ "aria-label": t("translation.ruleText"),
52896
+ "data-modal-autofocus": true,
52897
+ placeholder: t("translation.rulePlaceholder"),
52861
52898
  style: {
52862
- position: "relative",
52863
- display: "inline-flex",
52864
- alignItems: "center",
52865
- verticalAlign: "middle",
52866
- ...props.inline === true ? { marginInlineStart: 4 } : {}
52899
+ ...require_theme.dshSettingsFieldStyle,
52900
+ resize: "vertical"
52867
52901
  },
52868
- "data-codingns-translation-action": props.messageId
52869
- }, (0, react.createElement)("button", {
52870
- ref: buttonRef,
52871
- type: "button",
52872
- title: `${statusText} · ${props.translationT("translation.viewDetails")}`,
52873
- "aria-label": `${statusText} · ${props.translationT("translation.viewDetails")}`,
52874
- "aria-expanded": open,
52875
- "aria-controls": detailsId,
52876
- onClick: () => setOpen((value) => !value),
52877
- style: translationButtonStyle
52878
- }, (0, react.createElement)(TranslationGlyph), (0, react.createElement)("span", {
52879
- "aria-hidden": true,
52880
- "data-codingns-translation-pending": pending || void 0,
52902
+ onChange: (event) => {
52903
+ if (!disabled && draft !== null) setDraft({
52904
+ ...draft,
52905
+ text: event.currentTarget.value
52906
+ });
52907
+ }
52908
+ })), saveFailed && (0, react.createElement)("div", {
52909
+ role: "alert",
52881
52910
  style: {
52882
- ...TRANSLATION_STATUS_BADGE_STYLE,
52883
- ...pending ? TRANSLATION_PENDING_BADGE_STYLE : { background: statusColor }
52911
+ ...require_theme.dshSettingsHelpStyle,
52912
+ color: require_theme.dshThemeColor.error
52884
52913
  }
52885
- }, pending ? null : failed ? "!" : "✓")), renderedDetails);
52914
+ }, t("translation.saveRejected"))));
52886
52915
  }
52887
- function PendingTranslationActions(props) {
52888
- const anchorRef = (0, react.useRef)(null);
52889
- const [targets, setTargets] = (0, react.useState)([]);
52890
- const enabled = useCliSessionTranslationEnabled(props.sessionId, props.services.rpc);
52891
- const subagent = props.useSession?.((state) => state.subagent);
52892
- const eligible = enabled && subagent == null && !props.sessionId?.startsWith("codingns-assistant-");
52893
- (0, react.useLayoutEffect)(() => {
52894
- setTargets([]);
52895
- if (!eligible || anchorRef.current === null) return void 0;
52896
- return watchPendingTranslationTargets(anchorRef.current, setTargets);
52897
- }, [eligible, props.sessionId]);
52898
- return (0, react.createElement)("span", {
52899
- ref: anchorRef,
52900
- style: { display: "none" }
52901
- }, ...targets.map((target) => (0, import_react_dom.createPortal)((0, react.createElement)(PendingTranslationAction, {
52902
- services: props.services,
52903
- translationT: props.translationT,
52904
- original: target.original
52905
- }), target.container, String(target.key))));
52906
- }
52907
- function PendingTranslationAction(props) {
52908
- const id = (0, react.useId)();
52909
- return (0, react.createElement)(TranslationAction, {
52910
- ...props,
52911
- messageId: `pending-${id}`,
52912
- messageRole: "user",
52913
- popupAlign: "end"
52916
+ //#endregion
52917
+ //#region src/dsh-capabilities/types.ts
52918
+ function createCapabilityProfile(dshVersion, runtime, capabilities, diagnostics) {
52919
+ return Object.freeze({
52920
+ dshVersion,
52921
+ runtime,
52922
+ capabilities: freezeMap(capabilities),
52923
+ diagnostics: Object.freeze([...diagnostics]),
52924
+ frozenAt: Date.now()
52914
52925
  });
52915
52926
  }
52916
- function TranslationGlyph() {
52917
- return (0, react.createElement)("svg", {
52918
- viewBox: "0 0 24 24",
52919
- width: 16,
52920
- height: 16,
52921
- fill: "none",
52922
- stroke: "currentColor",
52923
- strokeWidth: 1.5,
52924
- strokeLinecap: "round",
52925
- strokeLinejoin: "round",
52926
- "aria-hidden": true
52927
- }, ...TRANSLATION_GLYPH_PATHS.map((d) => (0, react.createElement)("path", {
52928
- key: d,
52929
- d
52930
- })));
52927
+ /** Map 的只读视图,避免 Object.freeze(Map) 仍可通过 set() 修改。 */
52928
+ function freezeMap(source) {
52929
+ const map = new Map(source);
52930
+ const view = new Proxy(map, { get(target, property, receiver) {
52931
+ if (property === "set" || property === "delete" || property === "clear") return void 0;
52932
+ const value = Reflect.get(target, property, target);
52933
+ return typeof value === "function" ? value.bind(target) : value;
52934
+ } });
52935
+ return Object.freeze(view);
52931
52936
  }
52932
- const messageActionButtonStyle = {
52933
- position: "relative",
52934
- display: "inline-flex",
52935
- alignItems: "center",
52936
- justifyContent: "center",
52937
- width: 28,
52938
- height: 28,
52939
- padding: 0,
52940
- border: 0,
52941
- borderRadius: "var(--dsw-radius-sm, 6px)",
52942
- color: require_theme.dshThemeColor.labelTertiary,
52943
- background: "transparent",
52944
- cursor: "pointer"
52945
- };
52946
- const translationButtonStyle = {
52947
- ...messageActionButtonStyle,
52948
- transition: "background-color 100ms ease, color 100ms ease"
52949
- };
52950
- const translationDetailTypes = {
52951
- original: {
52952
- labelKey: "translation.originalText",
52953
- color: require_theme.dshThemeColor.labelSecondary
52954
- },
52955
- translated: {
52956
- labelKey: "translation.translatedText",
52957
- color: require_theme.dshThemeColor.accent
52958
- },
52959
- sent: {
52960
- labelKey: "translation.actualSentText",
52961
- color: require_theme.dshThemeColor.success
52937
+ //#endregion
52938
+ //#region src/dsh-capabilities/registry.ts
52939
+ var DshCapabilityRegistryError = class extends Error {
52940
+ code;
52941
+ capability;
52942
+ constructor(code, message, capability = null, options) {
52943
+ super(message, options);
52944
+ this.name = "DshCapabilityRegistryError";
52945
+ this.code = code;
52946
+ this.capability = capability;
52962
52947
  }
52963
52948
  };
52964
- function DetailBlock({ kind, translationT, value }) {
52965
- const { labelKey, color } = translationDetailTypes[kind];
52966
- return (0, react.createElement)("div", { style: { marginTop: 8 } }, (0, react.createElement)("div", { style: {
52967
- display: "inline-block",
52968
- maxWidth: "100%",
52969
- boxSizing: "border-box",
52970
- marginBottom: 6,
52971
- padding: "2px 8px",
52972
- border: `1px solid color-mix(in srgb, ${color} 30%, transparent)`,
52973
- borderRadius: "var(--dsw-radius-sm, 6px)",
52974
- color,
52975
- background: `color-mix(in srgb, ${color} 12%, transparent)`,
52976
- fontWeight: 600,
52977
- overflowWrap: "anywhere"
52978
- } }, translationT(labelKey)), (0, react.createElement)("pre", { style: {
52979
- margin: 0,
52980
- color: `color-mix(in srgb, ${color} 45%, ${require_theme.dshThemeColor.labelPrimary})`,
52981
- whiteSpace: "pre-wrap",
52982
- overflowWrap: "anywhere",
52983
- fontFamily: "inherit"
52984
- } }, value));
52985
- }
52986
- /** 按原生 user 节点的结构渲染用户消息;翻译入口只在确实有记录时追加。 */
52987
- function UserMessageNodeView(props) {
52988
- const data = props.node.data;
52989
- const parts = splitUserContent(data.content);
52990
- const record = readInputRecord({ source: data.source });
52991
- const translationRecord = record === void 0 ? void 0 : inputRecordForAction(record);
52992
- const labels = Array.isArray(data.referenceLabels) ? data.referenceLabels.filter((label) => typeof label === "string") : [];
52993
- const skillNames = Array.isArray(data.skillNames) ? data.skillNames.filter((name) => typeof name === "string") : [];
52994
- const showBubble = parts.text !== "" || parts.rest.length > 0;
52995
- const compactImages = parts.attachments.filter((attachment) => attachment.type === "image").length > 1;
52996
- const messageId = `user-${String(data.seq ?? props.node.id ?? "message")}`;
52997
- const chatT = props.t;
52998
- return (0, react.createElement)("div", {
52999
- "data-chat-flow-kind": "user",
53000
- style: {
53001
- display: "flex",
53002
- flexDirection: "column",
53003
- alignItems: "flex-end",
53004
- gap: 6
53005
- }
53006
- }, (0, react.createElement)("div", { style: {
53007
- display: "flex",
53008
- flexDirection: "column",
53009
- alignItems: "flex-end",
53010
- gap: 8,
53011
- minWidth: 0,
53012
- maxWidth: "min(calc(var(--dsh-chat-content-width, 748px) * .702), 82%)"
53013
- } }, parts.attachments.length > 0 ? (0, react.createElement)("div", {
53014
- "data-message-attachments": true,
53015
- style: {
53016
- display: "flex",
53017
- flexWrap: "wrap",
53018
- justifyContent: "flex-end",
53019
- gap: 8,
53020
- maxWidth: "100%"
53021
- }
53022
- }, ...parts.attachments.map((attachment, index) => attachment.type === "image" ? (0, react.createElement)("div", { key: `image-${index}` }, props.renderMessageImages({
53023
- images: [{ attachment: attachment.attachment }],
53024
- align: "end",
53025
- compact: compactImages
53026
- })) : createFileAttachment(attachment.file, index))) : null, showBubble ? (0, react.createElement)("div", { style: {
53027
- boxSizing: "border-box",
53028
- maxWidth: "100%",
53029
- padding: "10px 16px",
53030
- borderRadius: "var(--dsw-radius-xl, 18px)",
53031
- color: require_theme.dshThemeColor.labelPrimary,
53032
- background: "var(--dsw-specific-bubble, var(--dsw-alias-interactive-bg-hover, rgba(127,127,127,.08)))",
53033
- fontSize: "var(--dsh-content-font-size, 14px)",
53034
- lineHeight: "calc(22px + var(--dsh-content-font-delta, 0px))",
53035
- whiteSpace: "pre-wrap",
53036
- wordBreak: "break-word"
53037
- } }, (0, _deepseek_ai_dsh_client_ui_primitives.projectUserText)(parts.text, labels, skillNames, "skill", typeof props.openFile === "function" && typeof props.openSkill === "function" ? {
53038
- openFile: props.openFile,
53039
- openSkill: props.openSkill
53040
- } : void 0), ...parts.rest.map((block, index) => (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
53041
- key: `extra-${index}`,
53042
- label: chatT("message.extraBlock"),
53043
- payload: block,
53044
- truncatedLabel: (total) => chatT("json.truncated", { total })
53045
- }))) : null, labels.length === 0 ? null : (0, react.createElement)("div", { style: {
53046
- color: require_theme.dshThemeColor.labelTertiary,
53047
- fontSize: "var(--dsh-content-font-size-secondary, 13px)",
53048
- lineHeight: "calc(18px + var(--dsh-content-font-delta-secondary, 0px))"
53049
- } }, chatT("message.referenceSummary", { labels: labels.join(chatT("message.referenceSeparator")) }))), (0, react.createElement)("div", { style: {
53050
- display: "flex",
53051
- alignItems: "center",
53052
- alignSelf: "flex-end",
53053
- height: "calc(28px + var(--dsh-content-font-delta, 0px))",
53054
- gap: 8,
53055
- color: require_theme.dshThemeColor.labelTertiary
53056
- } }, typeof data.time === "number" ? (0, react.createElement)("span", { style: {
53057
- paddingRight: 12,
53058
- color: require_theme.dshThemeColor.labelTertiary,
53059
- fontSize: "var(--dsh-content-font-size-secondary, 13px)",
53060
- whiteSpace: "nowrap"
53061
- } }, formatMessageTime(data.time)) : null, translationRecord === void 0 ? null : (0, react.createElement)(TranslationAction, {
53062
- messageId,
53063
- messageRole: "user",
53064
- services: props.services,
53065
- translationT: props.translationT,
53066
- popupAlign: "end",
53067
- record: translationRecord
53068
- }), (0, react.createElement)(CopyAction, {
53069
- text: parts.text,
53070
- t: chatT
53071
- })));
53072
- }
53073
- function createFileAttachment(file, index) {
53074
- const name = typeof file.name === "string" ? file.name : "";
53075
- const bytes = typeof file.bytes === "number" ? file.bytes : 0;
53076
- return (0, react.createElement)("span", {
53077
- key: `file-${index}`,
53078
- title: name,
53079
- style: {
53080
- display: "inline-flex",
53081
- alignItems: "center",
53082
- minWidth: 0,
53083
- maxWidth: "100%",
53084
- gap: 8,
53085
- padding: "8px 10px",
53086
- border: `1px solid ${require_theme.dshThemeColor.border}`,
53087
- borderRadius: 8,
53088
- color: require_theme.dshThemeColor.labelPrimary,
53089
- background: require_theme.dshThemeColor.surfaceSubtle
52949
+ /** 集中解析 DSH 能力路由;Profile 生成后不可变,避免运行期替换半初始化服务。 */
52950
+ var DshCapabilityRegistry = class {
52951
+ dshVersion;
52952
+ runtime;
52953
+ routes = /* @__PURE__ */ new Map();
52954
+ profile;
52955
+ constructor(dshVersion, runtime) {
52956
+ this.dshVersion = dshVersion;
52957
+ this.runtime = runtime;
52958
+ }
52959
+ register(route) {
52960
+ validateRoute(route);
52961
+ if (route.runtime !== this.runtime) return;
52962
+ const list = this.routes.get(route.capability) ?? [];
52963
+ if (list.some((entry) => entry.id === route.id)) throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", `重复的能力路由: ${route.id}`, route.capability);
52964
+ list.push(route);
52965
+ this.routes.set(route.capability, list);
52966
+ this.profile = void 0;
52967
+ }
52968
+ registerMany(routes) {
52969
+ for (const route of routes) this.register(route);
52970
+ }
52971
+ resolve(context) {
52972
+ if (this.profile !== void 0) return this.profile;
52973
+ const resolutions = /* @__PURE__ */ new Map();
52974
+ const diagnostics = [];
52975
+ for (const [capability, routes] of this.routes) {
52976
+ const candidates = routes.filter((route) => isVersionInRange(this.dshVersion, route.supportedDsh)).sort((left, right) => routeRank(right) - routeRank(left));
52977
+ if (candidates.length === 0) {
52978
+ const reason = `DSH ${this.dshVersion} 没有能力 ${capability} 的适配路由`;
52979
+ resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
52980
+ diagnostics.push({
52981
+ code: "CAPABILITY_VERSION_UNSUPPORTED",
52982
+ capability,
52983
+ dshVersion: this.dshVersion,
52984
+ message: reason
52985
+ });
52986
+ continue;
52987
+ }
52988
+ const topPriority = routeRank(candidates[0]);
52989
+ const top = candidates.filter((route) => routeRank(route) === topPriority);
52990
+ if (top.length > 1) throw new DshCapabilityRegistryError("CAPABILITY_ROUTE_CONFLICT", `能力 ${capability} 存在同优先级路由: ${top.map((route) => route.id).join(", ")}`, capability);
52991
+ let selected;
52992
+ for (const route of candidates) try {
52993
+ if (route.detect(context)) {
52994
+ selected = route;
52995
+ break;
52996
+ }
52997
+ } catch (error) {
52998
+ diagnostics.push({
52999
+ code: "CAPABILITY_DETECT_FAILED",
53000
+ capability,
53001
+ routeId: route.id,
53002
+ dshVersion: this.dshVersion,
53003
+ message: `${route.id} 探测失败: ${errorMessage$1(error)}`,
53004
+ ...route.replacement === void 0 ? {} : { replacement: route.replacement }
53005
+ });
53006
+ }
53007
+ if (selected === void 0) {
53008
+ const reason = `DSH ${this.dshVersion} 的能力 ${capability} 没有可用运行时实现`;
53009
+ resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
53010
+ diagnostics.push({
53011
+ code: "CAPABILITY_UNAVAILABLE",
53012
+ capability,
53013
+ dshVersion: this.dshVersion,
53014
+ message: reason
53015
+ });
53016
+ continue;
53017
+ }
53018
+ try {
53019
+ const value = selected.create(context);
53020
+ const resolution = {
53021
+ capability,
53022
+ routeId: selected.id,
53023
+ dshVersion: this.dshVersion,
53024
+ status: selected.status === "deprecated" ? "degraded" : "ready",
53025
+ value,
53026
+ ...selected.replacement === void 0 ? {} : { replacement: selected.replacement }
53027
+ };
53028
+ resolutions.set(capability, resolution);
53029
+ if (selected.status === "deprecated") diagnostics.push({
53030
+ code: "CAPABILITY_DEPRECATED",
53031
+ capability,
53032
+ routeId: selected.id,
53033
+ dshVersion: this.dshVersion,
53034
+ message: `能力 ${capability} 使用已弃用路由 ${selected.id}`,
53035
+ ...selected.replacement === void 0 ? {} : { replacement: selected.replacement }
53036
+ });
53037
+ } catch (error) {
53038
+ const reason = `${selected.id} 创建失败: ${errorMessage$1(error)}`;
53039
+ resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
53040
+ diagnostics.push({
53041
+ code: "CAPABILITY_CREATE_FAILED",
53042
+ capability,
53043
+ routeId: selected.id,
53044
+ dshVersion: this.dshVersion,
53045
+ message: reason
53046
+ });
53047
+ }
53090
53048
  }
53091
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
53092
- path: name,
53093
- style: { flex: "none" }
53094
- }), (0, react.createElement)("span", { style: {
53095
- display: "flex",
53096
- flexDirection: "column",
53097
- minWidth: 0,
53098
- textAlign: "left"
53099
- } }, (0, react.createElement)("span", { style: {
53100
- overflow: "hidden",
53101
- textOverflow: "ellipsis",
53102
- whiteSpace: "nowrap"
53103
- } }, name), (0, react.createElement)("span", { style: {
53104
- color: require_theme.dshThemeColor.labelSecondary,
53105
- fontSize: 11
53106
- } }, [(0, _deepseek_ai_dsh_client_ui_primitives.fileExtension)(name).toUpperCase().slice(0, 8), (0, _deepseek_ai_dsh_client_ui_primitives.fileSizeText)(bytes)].filter(Boolean).join(" "))));
53049
+ this.profile = createCapabilityProfile(this.dshVersion, this.runtime, resolutions, diagnostics);
53050
+ return this.profile;
53051
+ }
53052
+ getProfile(context) {
53053
+ return this.resolve(context);
53054
+ }
53055
+ require(profile, capability) {
53056
+ const resolution = profile.capabilities.get(capability);
53057
+ if (resolution?.value === void 0 || resolution.status === "unavailable") throw new DshCapabilityRegistryError("CAPABILITY_UNAVAILABLE", resolution?.reason ?? `能力不可用: ${capability}`, capability);
53058
+ return resolution.value;
53059
+ }
53060
+ explain(profile, capability) {
53061
+ if (capability === void 0) return profile.diagnostics;
53062
+ return profile.diagnostics.filter((item) => item.capability === capability);
53063
+ }
53064
+ };
53065
+ function validateRoute(route) {
53066
+ if (route.id.trim() === "" || route.capability === void 0 || route.supportedDsh.trim() === "") throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", "能力路由必须包含 id、capability 和 supportedDsh");
53067
+ if (!Number.isFinite(route.priority)) throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", `能力路由优先级非法: ${route.id}`, route.capability);
53068
+ if (typeof route.detect !== "function" || typeof route.create !== "function") throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", `能力路由缺少探测或工厂: ${route.id}`, route.capability);
53107
53069
  }
53108
- function CopyAction({ text, t: chatT }) {
53109
- const [copied, setCopied] = (0, react.useState)(false);
53110
- const timer = (0, react.useRef)(void 0);
53111
- (0, react.useEffect)(() => () => {
53112
- if (timer.current !== void 0) clearTimeout(timer.current);
53113
- }, []);
53114
- return (0, react.createElement)("button", {
53115
- type: "button",
53116
- title: copied ? chatT("copied") : chatT("copy"),
53117
- "aria-label": copied ? chatT("copied") : chatT("copy"),
53118
- onClick: () => {
53119
- (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(text).then((success) => {
53120
- if (!success) return;
53121
- setCopied(true);
53122
- if (timer.current !== void 0) clearTimeout(timer.current);
53123
- timer.current = setTimeout(() => {
53124
- timer.current = void 0;
53125
- setCopied(false);
53126
- }, 1e3);
53127
- });
53128
- },
53129
- style: messageActionButtonStyle
53130
- }, (0, react.createElement)(copied ? _deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular : _deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular));
53070
+ function routeRank(route) {
53071
+ return route.priority + (route.status === "supported" ? 1e6 : 0);
53131
53072
  }
53132
- function splitUserContent(content) {
53133
- const text = [];
53134
- const attachments = [];
53135
- const rest = [];
53136
- if (typeof content === "string") return {
53137
- text: content,
53138
- attachments,
53139
- rest
53140
- };
53141
- if (!Array.isArray(content)) return {
53142
- text: "",
53143
- attachments,
53144
- rest
53145
- };
53146
- for (const value of content) {
53147
- const block = asRecord(value);
53148
- if (block?.type === "text" && typeof block.text === "string") text.push(block.text);
53149
- else if (block?.type === "image" && block.attachment !== void 0) attachments.push({
53150
- type: "image",
53151
- attachment: block.attachment
53152
- });
53153
- else if (block?.type === "file" && asRecord(block.attachment) !== void 0) attachments.push({
53154
- type: "file",
53155
- file: asRecord(block.attachment)
53156
- });
53157
- else rest.push(value);
53158
- }
53073
+ function unavailable(capability, dshVersion, reason) {
53159
53074
  return {
53160
- text: text.join(""),
53161
- attachments,
53162
- rest
53075
+ capability,
53076
+ dshVersion,
53077
+ status: "unavailable",
53078
+ reason
53163
53079
  };
53164
53080
  }
53165
- function formatMessageTime(time) {
53166
- const date = new Date(time);
53167
- const now = /* @__PURE__ */ new Date();
53168
- const options = date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate() ? {
53169
- hour: "2-digit",
53170
- minute: "2-digit"
53171
- } : {
53172
- ...date.getFullYear() === now.getFullYear() ? {} : { year: "numeric" },
53173
- month: "2-digit",
53174
- day: "2-digit",
53175
- hour: "2-digit",
53176
- minute: "2-digit"
53081
+ function isVersionInRange(version, range) {
53082
+ const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(range);
53083
+ if (match === null) return false;
53084
+ const actual = parseVersion(version);
53085
+ const minimum = parseVersion(match[1]);
53086
+ if (actual === void 0 || minimum === void 0) return false;
53087
+ if (match[2] === void 0) return compareVersions(actual, minimum) >= 0;
53088
+ const maximum = parseVersion(match[2]);
53089
+ if (maximum === void 0) return false;
53090
+ return compareVersions(actual, minimum) >= 0 && compareVersions(actual, maximum) <= 0;
53091
+ }
53092
+ function parseVersion(value) {
53093
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(value);
53094
+ if (match === null) return void 0;
53095
+ return {
53096
+ major: Number(match[1]),
53097
+ minor: Number(match[2]),
53098
+ patch: Number(match[3]),
53099
+ pre: match[4] === void 0 ? [] : match[4].split(".").map((part) => /^\d+$/u.test(part) ? Number(part) : part)
53177
53100
  };
53178
- return new Intl.DateTimeFormat(void 0, options).format(date);
53179
53101
  }
53180
- /** DSH assistant-step renderer: keep each translation action adjacent to its source block. */
53181
- function AssistantTranslationNodeView(props) {
53182
- const data = props.node.data;
53183
- const blocks = Array.isArray(data.blocks) ? data.blocks : [];
53184
- const streaming = data.status === "running";
53185
- const chatT = props.t;
53186
- const markdownLabels = (0, react.useMemo)(() => createMarkdownLabels(chatT), [chatT]);
53187
- const pathImages = (0, react.useMemo)(() => ({ resolve: resolveMarkdownImagePath }), []);
53188
- const renderable = streaming || data.status === "interrupted" || blocks.some((block) => block.kind !== "tool-call");
53189
- const eventSnapshot = renderable ? readEventSource(props.services, props.sessionId)?.getSnapshot() : void 0;
53190
- const hasTranslation = renderable && blocks.some((block) => {
53191
- if (block.kind !== "reasoning" && block.kind !== "text") return false;
53192
- const outputKind = block.kind === "reasoning" ? "reasoning" : "assistant";
53193
- const embedded = readRecord(block);
53194
- if (embedded !== void 0 && (embedded.outputKind === void 0 || embedded.outputKind === outputKind)) return true;
53195
- return eventSnapshot !== void 0 && findTranslationRecordForText(eventSnapshot, block.text, outputKind, data.turn, data.step) !== void 0;
53196
- });
53197
- const turn = props.node.location?.kind === "turn" || props.node.location?.kind === "step" ? props.node.location.turn : void 0;
53198
- const tail = typeof props.useTurnData === "function" ? props.useTurnData("turn-tail") : void 0;
53199
- const finalNode = data.finalNode;
53200
- const fileOwner = turn?.status === "closed" && finalNode !== void 0 && tail?.closing?.finalNode?.seq === finalNode.seq ? {
53201
- turn,
53202
- seq: finalNode.seq,
53203
- openFile: (path) => {
53204
- props.openFile(path);
53205
- }
53206
- } : void 0;
53207
- const mentions = fileOwner === void 0 || typeof props.fileMentions !== "function" ? void 0 : props.fileMentions(fileOwner);
53208
- const turnProcess = props.turnProcess;
53209
- const reasoningHidden = turnProcess !== void 0 && turnProcess.foldable === true && turnProcess.spec?.answerStep === data.step && turnProcess.spec?.inlineReasoning === true && turnProcess.open !== true;
53210
- const rendered = [];
53211
- const last = blocks.length - 1;
53212
- const messageId = typeof finalNode?.messageId === "string" ? finalNode.messageId : `turn-${data.turn}-step-${data.step}`;
53213
- if (!renderable) return null;
53214
- for (let index = 0; index < blocks.length; index += 1) {
53215
- const block = blocks[index];
53216
- if (block === void 0) continue;
53217
- if (props.groupPart === "reasoning" && block.kind !== "reasoning") continue;
53218
- if (props.groupPart === "response" && block.kind === "reasoning") continue;
53219
- const running = streaming && index === last;
53220
- if (block.kind === "text") {
53221
- const translationRecord = readRecord(block) ?? (hasTranslation && eventSnapshot !== void 0 ? findTranslationRecordForText(eventSnapshot, block.text, "assistant", data.turn, data.step) : void 0);
53222
- const displayText = translationRecord?.translated ?? block.text;
53223
- rendered.push((0, react.createElement)("div", {
53224
- key: `text-${index}`,
53225
- "data-codingns-translation-inline": true,
53226
- style: { minWidth: 0 }
53227
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
53228
- text: displayText,
53229
- streaming,
53230
- labels: markdownLabels,
53231
- fileMentions: mentions,
53232
- pathImages
53233
- }), translationRecord === void 0 ? null : (0, react.createElement)(TranslationAction, {
53234
- messageId: `${messageId}-text-${index}`,
53235
- messageRole: "assistant",
53236
- services: props.services,
53237
- translationT: props.translationT,
53238
- record: translationRecord,
53239
- inline: true
53240
- })));
53241
- continue;
53242
- }
53243
- if (block.kind === "reasoning") {
53244
- const translationRecord = readRecord(block) ?? (hasTranslation && eventSnapshot !== void 0 ? findTranslationRecordForText(eventSnapshot, block.text, "reasoning", data.turn, data.step) : void 0);
53245
- rendered.push((0, react.createElement)(AssistantReasoningBlock, {
53246
- key: `reasoning-${index}`,
53247
- messageId: `${messageId}-reasoning-${index}`,
53248
- services: props.services,
53249
- translationT: props.translationT,
53250
- chatT,
53251
- text: block.text,
53252
- ...translationRecord === void 0 ? {} : { translationRecord },
53253
- running,
53254
- hidden: reasoningHidden,
53255
- reveal: () => turnProcess?.setOpen?.(true),
53256
- useGroupAction: props.useGroupAction,
53257
- renderFactorySlot: props.renderFactorySlot,
53258
- markdownLabels,
53259
- pathImages,
53260
- mentions
53261
- }));
53262
- continue;
53263
- }
53264
- if (block.kind === "image") {
53265
- const imageGroup = [block];
53266
- while (index + 1 < blocks.length && blocks[index + 1]?.kind === "image") {
53267
- const next = blocks[index + 1];
53268
- if (next?.kind !== "image") break;
53269
- imageGroup.push(next);
53270
- index += 1;
53271
- }
53272
- rendered.push((0, react.createElement)("div", {
53273
- key: `images-${index}`,
53274
- style: { alignSelf: "flex-start" }
53275
- }, props.renderMessageImages({
53276
- images: imageGroup.map((image) => ({ attachment: image.attachment })),
53277
- align: "start"
53278
- })));
53279
- continue;
53280
- }
53281
- if (block.kind === "other") rendered.push((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
53282
- key: `other-${index}`,
53283
- label: chatT("message.unknownBlock"),
53284
- payload: block.block,
53285
- truncatedLabel: (total) => chatT("json.truncated", { total })
53286
- }));
53102
+ function compareVersions(left, right) {
53103
+ for (const key of [
53104
+ "major",
53105
+ "minor",
53106
+ "patch"
53107
+ ]) if (left[key] !== right[key]) return left[key] - right[key];
53108
+ if (left.pre.length === 0 && right.pre.length > 0) return 1;
53109
+ if (left.pre.length > 0 && right.pre.length === 0) return -1;
53110
+ for (let index = 0; index < Math.max(left.pre.length, right.pre.length); index += 1) {
53111
+ const a = left.pre[index];
53112
+ const b = right.pre[index];
53113
+ if (a === void 0) return -1;
53114
+ if (b === void 0) return 1;
53115
+ if (a === b) continue;
53116
+ if (typeof a === "number" && typeof b === "string") return -1;
53117
+ if (typeof a === "string" && typeof b === "number") return 1;
53118
+ return a < b ? -1 : 1;
53287
53119
  }
53288
- return (0, react.createElement)("div", {
53289
- "data-streaming": streaming || void 0,
53290
- style: {
53291
- display: "flex",
53292
- flexDirection: "column",
53293
- gap: 16,
53294
- minWidth: 0,
53295
- color: require_theme.dshThemeColor.labelPrimary,
53296
- fontSize: "var(--dsh-content-font-size, 14px)",
53297
- lineHeight: "calc(24px + var(--dsh-content-font-delta, 0px))"
53298
- }
53299
- }, ...rendered, data.status === "interrupted" ? (0, react.createElement)("span", { style: {
53300
- alignSelf: "flex-start",
53301
- padding: "0 6px",
53302
- borderRadius: "var(--dsw-radius-sm, 4px)",
53303
- color: require_theme.dshThemeColor.labelTertiary,
53304
- background: require_theme.dshThemeColor.surfaceSubtle,
53305
- fontSize: 11,
53306
- lineHeight: "18px"
53307
- } }, chatT("message.stopped")) : null);
53120
+ return 0;
53308
53121
  }
53309
- function AssistantReasoningBlock(props) {
53310
- const [expanded, setExpanded] = (0, react.useState)(false);
53311
- const groupRef = props.useGroupAction?.(props.hidden, props.reveal);
53312
- const summary = (props.translationRecord?.translated ?? props.text).split("\n").map((line) => line.replace(/[`*_#>]/gu, "").trim()).find(Boolean) ?? "";
53313
- return (0, react.createElement)("div", {
53314
- ref: groupRef,
53315
- hidden: props.hidden,
53316
- "data-turn-process-inline": props.hidden || void 0
53317
- }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
53318
- icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconThinkOutlineRegular, { size: 14 }),
53319
- title: props.chatT("message.think"),
53320
- open: expanded,
53321
- expandable: true,
53322
- expandOnRowClick: true,
53323
- running: props.running,
53324
- onToggle: () => setExpanded((value) => !value),
53325
- collapsedContent: (0, react.createElement)("span", { style: {
53326
- minWidth: 0,
53327
- overflow: "hidden",
53328
- color: require_theme.dshThemeColor.labelSecondary,
53329
- fontSize: "var(--dsh-content-font-size-secondary, 13px)",
53330
- textOverflow: "ellipsis",
53331
- whiteSpace: "nowrap"
53332
- } }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.TextShimmer, {
53333
- active: props.running,
53334
- children: summary
53335
- }))
53336
- }, expanded ? (0, react.createElement)(AssistantReasoningContent, {
53337
- messageId: props.messageId,
53338
- services: props.services,
53339
- translationT: props.translationT,
53340
- text: props.text,
53341
- running: props.running,
53342
- ...props.translationRecord === void 0 ? {} : { translationRecord: props.translationRecord },
53343
- markdownLabels: props.markdownLabels,
53344
- pathImages: props.pathImages,
53345
- mentions: props.mentions,
53346
- ...props.renderFactorySlot === void 0 ? {} : { renderFactorySlot: props.renderFactorySlot }
53347
- }) : null));
53122
+ function errorMessage$1(error) {
53123
+ return error instanceof Error ? error.message : String(error);
53348
53124
  }
53349
- /**
53350
- * 思考块展开后的正文。
53351
- *
53352
- * DSH 原生 `ReasoningRow` 直接渲染 `MarkdownText`,运行时**没有**注册
53353
- * `conversation.chat.reasoning.content` 工厂(`conversation.chat.*` 只有
53354
- * `node` / `assistant-actions` / `commandview` / `turnTail`)。而 `renderFactorySlot`
53355
- * 在工厂缺失时只渲染 `fallback`,缺省为 `null`——此前这里既不传 fallback,
53356
- * 又把正文完全交给该工厂,于是展开思考后只剩翻译入口,译文一行都看不到。
53357
- * 因此原生 MarkdownText 必须作为 fallback 传进去:没有工厂时按原生方式渲染,
53358
- * 工厂存在时才允许表现层覆盖。
53359
- */
53360
- function AssistantReasoningContent(props) {
53361
- const displayText = props.translationRecord?.translated ?? props.text;
53362
- const markdown = (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
53363
- text: displayText,
53364
- streaming: props.running,
53365
- labels: props.markdownLabels,
53366
- fileMentions: props.mentions,
53367
- pathImages: props.pathImages,
53368
- variant: "compact"
53369
- });
53370
- const content = props.renderFactorySlot === void 0 ? markdown : props.renderFactorySlot("conversation.chat.reasoning.content", {
53371
- text: displayText,
53372
- running: props.running
53373
- }, { fallback: markdown });
53374
- return (0, react.createElement)("div", {
53375
- "data-codingns-translation-inline": true,
53376
- style: { paddingTop: 8 }
53377
- }, content, props.translationRecord === void 0 ? null : (0, react.createElement)(TranslationAction, {
53378
- messageId: props.messageId,
53379
- messageRole: "assistant",
53380
- services: props.services,
53381
- translationT: props.translationT,
53382
- record: props.translationRecord,
53383
- inline: true
53384
- }));
53125
+ //#endregion
53126
+ //#region src/dsh-capabilities/client/terminal-sharing-adapter.ts
53127
+ /** DSH 版本差异只在本适配器探测,终端业务不读取宿主私有编辑器。 */
53128
+ function supportsTerminalSharing(context) {
53129
+ return typeof service(context, "sessions")?.scope === "function" && typeof service(context, "conversation")?.input?.for === "function" && typeof service(context, "uiWorkspace")?.openSession === "function";
53385
53130
  }
53386
- function createMarkdownLabels(chatT) {
53387
- return {
53388
- code: {
53389
- copyLabel: chatT("copy"),
53390
- copiedLabel: chatT("copied"),
53391
- toolbarLabels: {
53392
- codeLabel: chatT("codeBlock.title"),
53393
- wrapLabel: chatT("codeBlock.wrap"),
53394
- unwrapLabel: chatT("codeBlock.unwrap")
53395
- }
53396
- },
53397
- footnotes: chatT("markdown.footnotes")
53398
- };
53399
- }
53400
- function resolveMarkdownImagePath(value) {
53401
- if (typeof document === "undefined" || !value.startsWith("/") || /^[/\\]{2}/u.test(value) || /[\u0000-\u001f\u007f]/u.test(value)) return void 0;
53402
- const base = document.baseURI;
53403
- if (!/^https?:/u.test(base) && !base.startsWith("dsh-app://app/")) return void 0;
53404
- try {
53405
- return new URL(`api/file?path=${encodeURIComponent(value)}`, base).href;
53406
- } catch {
53407
- return;
53408
- }
53409
- }
53410
- /**
53411
- * 注册两个有实际翻译记录的消息渲染器;DSH 的用户气泡内容仍由统一主题令牌控制。
53412
- */
53413
- function registerSessionTranslationChatUi(services) {
53414
- const slots = services.slots;
53415
- if (slots?.inject === void 0 || slots.register === void 0) return () => void 0;
53416
- const removeStyles = installSessionTranslationChatStyles();
53417
- const translationT = services.locale.bind("codingns");
53418
- const removePendingActions = slots.inject("conversation.input.left", () => slots.register({
53419
- name: "conversation.input.left",
53420
- id: "codingns-translation-pending",
53421
- inject: (sessionId) => ({
53422
- services,
53423
- sessionId,
53424
- translationT
53425
- })
53426
- }, PendingTranslationActions));
53427
- const removeUserRenderer = slots.inject("conversation.chat.node", () => slots.register({
53428
- name: "conversation.chat.node",
53429
- key: "user",
53430
- priority: -100,
53431
- locale: "chat",
53432
- inject: (sessionId) => ({
53433
- services,
53434
- sessionId,
53435
- translationT
53436
- })
53437
- }, UserMessageNodeView));
53438
- const removeAssistantRenderer = slots.inject("conversation.chat.node", () => slots.register({
53439
- name: "conversation.chat.node",
53440
- key: "assistant-step",
53441
- priority: -100,
53442
- locale: "chat",
53443
- inject: (sessionId) => ({
53444
- services,
53445
- sessionId,
53446
- translationT
53447
- })
53448
- }, AssistantTranslationNodeView));
53449
- return () => {
53450
- removePendingActions();
53451
- removeAssistantRenderer();
53452
- removeUserRenderer();
53453
- removeStyles();
53454
- };
53455
- }
53456
- function installSessionTranslationChatStyles() {
53457
- if (typeof document === "undefined") return () => void 0;
53458
- const styleId = "codingns-session-translation-chat";
53459
- if (document.head.querySelector(`style[data-plugin-css="${styleId}"]`) !== null) return () => void 0;
53460
- const style = document.createElement("style");
53461
- style.dataset.plugin = "codingns4dsh";
53462
- style.dataset.pluginCss = styleId;
53463
- style.textContent = `
53464
- @keyframes codingns-translation-spin{to{transform:rotate(360deg)}}
53465
- [data-codingns-translation-pending]{animation:codingns-translation-spin .8s linear infinite}
53466
- @media(prefers-reduced-motion:reduce){[data-codingns-translation-pending]{animation-duration:1.6s}}
53467
- [data-codingns-translation-inline] > div:not([data-codingns-translation-action]){display:contents}
53468
- [data-codingns-translation-inline] > div:not([data-codingns-translation-action]) > p:last-child{display:inline;margin:0}
53469
- `;
53470
- document.head.appendChild(style);
53471
- return () => style.remove();
53472
- }
53473
- function readEventSource(services, sessionId) {
53474
- const sessions = services.sessions;
53475
- try {
53476
- return sessions?.binding?.(sessionId)?.eventSource;
53477
- } catch {
53478
- return;
53479
- }
53480
- }
53481
- function findTranslationRecordForText(snapshot, text, outputKind, turn, step) {
53482
- const entries = snapshot.entries ?? [];
53483
- for (let index = entries.length - 1; index >= 0; index -= 1) {
53484
- const event = readEntryEvent(entries[index]);
53485
- if (event === void 0 || !event.type.startsWith("assistant/")) continue;
53486
- const eventData = asRecord(event.data);
53487
- if (turn !== void 0 && typeof eventData?.turn === "number" && eventData.turn !== turn) continue;
53488
- if (step !== void 0 && typeof eventData?.step === "number" && eventData.step !== step) continue;
53489
- const candidates = [];
53490
- collectRecordCandidates(event.data, candidates, /* @__PURE__ */ new Set());
53491
- for (const candidate of candidates) {
53492
- const record = readRecord(candidate);
53493
- if (record === void 0 || record.original !== text && record.translated !== text) continue;
53494
- if (outputKind !== void 0 && record.outputKind !== void 0 && record.outputKind !== outputKind) continue;
53495
- return record;
53496
- }
53497
- }
53498
- }
53499
- function collectRecordCandidates(value, candidates, seen, depth = 0) {
53500
- if (Array.isArray(value)) {
53501
- for (const item of value) collectRecordCandidates(item, candidates, seen, depth + 1);
53502
- return;
53503
- }
53504
- const record = asRecord(value);
53505
- if (record === void 0 || seen.has(record) || depth > 7) return;
53506
- seen.add(record);
53507
- if (readRecord(record) !== void 0 || asRecord(record.codingnsTranslation) !== void 0) candidates.push(record);
53508
- for (const key of [
53509
- "codingnsTranslation",
53510
- "source",
53511
- "message",
53512
- "content",
53513
- "stream",
53514
- "chunk",
53515
- "block",
53516
- "data"
53517
- ]) if (record[key] !== void 0) collectRecordCandidates(record[key], candidates, seen, depth + 1);
53518
- }
53519
- function readEntryEvent(value) {
53520
- const record = asRecord(value);
53521
- return asRecord(record?.event) ?? (typeof record?.type === "string" ? record : void 0);
53522
- }
53523
- function readRecord(value) {
53524
- const record = asRecord(value);
53525
- const candidate = asRecord(record?.codingnsTranslation) ?? record;
53526
- if (candidate?.original === void 0 || candidate.translated === void 0) return void 0;
53527
- if (typeof candidate.original !== "string" || typeof candidate.translated !== "string") return void 0;
53528
- const targetLanguage = readLanguage(candidate.targetLanguage);
53529
- if (targetLanguage === void 0) return void 0;
53530
- const model = readModel(candidate.model);
53531
- const outputKind = candidate.outputKind === "assistant" || candidate.outputKind === "reasoning" ? candidate.outputKind : void 0;
53532
- return {
53533
- original: candidate.original,
53534
- translated: candidate.translated,
53535
- ...candidate.sourceLanguage === "zh" || candidate.sourceLanguage === "en" || candidate.sourceLanguage === "fr" || candidate.sourceLanguage === "de" || candidate.sourceLanguage === "ja" ? { sourceLanguage: candidate.sourceLanguage } : {},
53536
- targetLanguage,
53537
- bilingual: candidate.bilingual === true,
53538
- ...outputKind === void 0 ? {} : { outputKind },
53539
- ...candidate.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
53540
- ...model === void 0 ? {} : { model },
53541
- ...candidate.failed === true ? { failed: true } : {},
53542
- ...require_session_translation.readSessionTranslationMetrics(candidate)
53543
- };
53544
- }
53545
- function readModel(value) {
53546
- const record = asRecord(value);
53547
- if (typeof record?.provider !== "string" || typeof record.model !== "string" || record.provider.trim() === "" || record.model.trim() === "") return void 0;
53548
- return {
53549
- provider: record.provider,
53550
- model: record.model
53551
- };
53552
- }
53553
- function readInputRecord(value) {
53554
- const candidate = asRecord(asRecord(asRecord(value)?.source)?.codingnsTranslationInput);
53555
- if (candidate?.original === void 0 || candidate.translated === void 0) return void 0;
53556
- if (typeof candidate.original !== "string" || typeof candidate.translated !== "string") return void 0;
53557
- const targetLanguage = readLanguage(candidate.targetLanguage);
53558
- if (targetLanguage === void 0) return void 0;
53559
- const model = readModel(candidate.model);
53560
- return {
53561
- original: candidate.original,
53562
- translated: candidate.translated,
53563
- ...candidate.sourceLanguage === "zh" || candidate.sourceLanguage === "en" || candidate.sourceLanguage === "fr" || candidate.sourceLanguage === "de" || candidate.sourceLanguage === "ja" ? { sourceLanguage: candidate.sourceLanguage } : {},
53564
- targetLanguage,
53565
- ...candidate.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
53566
- ...model === void 0 ? {} : { model },
53567
- ...candidate.failed === true ? { failed: true } : {},
53568
- ...require_session_translation.readSessionTranslationMetrics(candidate)
53569
- };
53570
- }
53571
- function inputRecordForAction(record) {
53572
- return {
53573
- original: record.original,
53574
- translated: record.translated,
53575
- ...record.sourceLanguage === void 0 ? {} : { sourceLanguage: record.sourceLanguage },
53576
- targetLanguage: record.targetLanguage,
53577
- bilingual: false,
53578
- ...record.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
53579
- ...record.model === void 0 ? {} : { model: record.model },
53580
- ...record.failed === true ? { failed: true } : {},
53581
- ...require_session_translation.readSessionTranslationMetrics(record)
53582
- };
53583
- }
53584
- function readLanguage(value) {
53585
- return value === "zh" || value === "en" || value === "fr" || value === "de" || value === "ja" ? value : void 0;
53586
- }
53587
- function formatModel(model, t) {
53588
- return model === void 0 ? t("translation.modelUnknown") : `${model.provider} / ${model.model}`;
53589
- }
53590
- function safeDomId(value) {
53591
- return encodeURIComponent(value).replace(/%/gu, "-");
53592
- }
53593
- function asRecord(value) {
53594
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
53595
- }
53596
- //#endregion
53597
- //#region src/dsh-capabilities/types.ts
53598
- function createCapabilityProfile(dshVersion, runtime, capabilities, diagnostics) {
53599
- return Object.freeze({
53600
- dshVersion,
53601
- runtime,
53602
- capabilities: freezeMap(capabilities),
53603
- diagnostics: Object.freeze([...diagnostics]),
53604
- frozenAt: Date.now()
53605
- });
53606
- }
53607
- /** Map 的只读视图,避免 Object.freeze(Map) 仍可通过 set() 修改。 */
53608
- function freezeMap(source) {
53609
- const map = new Map(source);
53610
- const view = new Proxy(map, { get(target, property, receiver) {
53611
- if (property === "set" || property === "delete" || property === "clear") return void 0;
53612
- const value = Reflect.get(target, property, target);
53613
- return typeof value === "function" ? value.bind(target) : value;
53614
- } });
53615
- return Object.freeze(view);
53616
- }
53617
- //#endregion
53618
- //#region src/dsh-capabilities/registry.ts
53619
- var DshCapabilityRegistryError = class extends Error {
53620
- code;
53621
- capability;
53622
- constructor(code, message, capability = null, options) {
53623
- super(message, options);
53624
- this.name = "DshCapabilityRegistryError";
53625
- this.code = code;
53626
- this.capability = capability;
53627
- }
53628
- };
53629
- /** 集中解析 DSH 能力路由;Profile 生成后不可变,避免运行期替换半初始化服务。 */
53630
- var DshCapabilityRegistry = class {
53631
- dshVersion;
53632
- runtime;
53633
- routes = /* @__PURE__ */ new Map();
53634
- profile;
53635
- constructor(dshVersion, runtime) {
53636
- this.dshVersion = dshVersion;
53637
- this.runtime = runtime;
53638
- }
53639
- register(route) {
53640
- validateRoute(route);
53641
- if (route.runtime !== this.runtime) return;
53642
- const list = this.routes.get(route.capability) ?? [];
53643
- if (list.some((entry) => entry.id === route.id)) throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", `重复的能力路由: ${route.id}`, route.capability);
53644
- list.push(route);
53645
- this.routes.set(route.capability, list);
53646
- this.profile = void 0;
53647
- }
53648
- registerMany(routes) {
53649
- for (const route of routes) this.register(route);
53650
- }
53651
- resolve(context) {
53652
- if (this.profile !== void 0) return this.profile;
53653
- const resolutions = /* @__PURE__ */ new Map();
53654
- const diagnostics = [];
53655
- for (const [capability, routes] of this.routes) {
53656
- const candidates = routes.filter((route) => isVersionInRange(this.dshVersion, route.supportedDsh)).sort((left, right) => routeRank(right) - routeRank(left));
53657
- if (candidates.length === 0) {
53658
- const reason = `DSH ${this.dshVersion} 没有能力 ${capability} 的适配路由`;
53659
- resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
53660
- diagnostics.push({
53661
- code: "CAPABILITY_VERSION_UNSUPPORTED",
53662
- capability,
53663
- dshVersion: this.dshVersion,
53664
- message: reason
53665
- });
53666
- continue;
53667
- }
53668
- const topPriority = routeRank(candidates[0]);
53669
- const top = candidates.filter((route) => routeRank(route) === topPriority);
53670
- if (top.length > 1) throw new DshCapabilityRegistryError("CAPABILITY_ROUTE_CONFLICT", `能力 ${capability} 存在同优先级路由: ${top.map((route) => route.id).join(", ")}`, capability);
53671
- let selected;
53672
- for (const route of candidates) try {
53673
- if (route.detect(context)) {
53674
- selected = route;
53675
- break;
53676
- }
53677
- } catch (error) {
53678
- diagnostics.push({
53679
- code: "CAPABILITY_DETECT_FAILED",
53680
- capability,
53681
- routeId: route.id,
53682
- dshVersion: this.dshVersion,
53683
- message: `${route.id} 探测失败: ${errorMessage$1(error)}`,
53684
- ...route.replacement === void 0 ? {} : { replacement: route.replacement }
53685
- });
53686
- }
53687
- if (selected === void 0) {
53688
- const reason = `DSH ${this.dshVersion} 的能力 ${capability} 没有可用运行时实现`;
53689
- resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
53690
- diagnostics.push({
53691
- code: "CAPABILITY_UNAVAILABLE",
53692
- capability,
53693
- dshVersion: this.dshVersion,
53694
- message: reason
53695
- });
53696
- continue;
53697
- }
53698
- try {
53699
- const value = selected.create(context);
53700
- const resolution = {
53701
- capability,
53702
- routeId: selected.id,
53703
- dshVersion: this.dshVersion,
53704
- status: selected.status === "deprecated" ? "degraded" : "ready",
53705
- value,
53706
- ...selected.replacement === void 0 ? {} : { replacement: selected.replacement }
53707
- };
53708
- resolutions.set(capability, resolution);
53709
- if (selected.status === "deprecated") diagnostics.push({
53710
- code: "CAPABILITY_DEPRECATED",
53711
- capability,
53712
- routeId: selected.id,
53713
- dshVersion: this.dshVersion,
53714
- message: `能力 ${capability} 使用已弃用路由 ${selected.id}`,
53715
- ...selected.replacement === void 0 ? {} : { replacement: selected.replacement }
53716
- });
53717
- } catch (error) {
53718
- const reason = `${selected.id} 创建失败: ${errorMessage$1(error)}`;
53719
- resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
53720
- diagnostics.push({
53721
- code: "CAPABILITY_CREATE_FAILED",
53722
- capability,
53723
- routeId: selected.id,
53724
- dshVersion: this.dshVersion,
53725
- message: reason
53726
- });
53727
- }
53728
- }
53729
- this.profile = createCapabilityProfile(this.dshVersion, this.runtime, resolutions, diagnostics);
53730
- return this.profile;
53731
- }
53732
- getProfile(context) {
53733
- return this.resolve(context);
53734
- }
53735
- require(profile, capability) {
53736
- const resolution = profile.capabilities.get(capability);
53737
- if (resolution?.value === void 0 || resolution.status === "unavailable") throw new DshCapabilityRegistryError("CAPABILITY_UNAVAILABLE", resolution?.reason ?? `能力不可用: ${capability}`, capability);
53738
- return resolution.value;
53739
- }
53740
- explain(profile, capability) {
53741
- if (capability === void 0) return profile.diagnostics;
53742
- return profile.diagnostics.filter((item) => item.capability === capability);
53743
- }
53744
- };
53745
- function validateRoute(route) {
53746
- if (route.id.trim() === "" || route.capability === void 0 || route.supportedDsh.trim() === "") throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", "能力路由必须包含 id、capability 和 supportedDsh");
53747
- if (!Number.isFinite(route.priority)) throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", `能力路由优先级非法: ${route.id}`, route.capability);
53748
- if (typeof route.detect !== "function" || typeof route.create !== "function") throw new DshCapabilityRegistryError("CAPABILITY_INVALID_ROUTE", `能力路由缺少探测或工厂: ${route.id}`, route.capability);
53749
- }
53750
- function routeRank(route) {
53751
- return route.priority + (route.status === "supported" ? 1e6 : 0);
53752
- }
53753
- function unavailable(capability, dshVersion, reason) {
53754
- return {
53755
- capability,
53756
- dshVersion,
53757
- status: "unavailable",
53758
- reason
53759
- };
53760
- }
53761
- function isVersionInRange(version, range) {
53762
- const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(range);
53763
- if (match === null) return false;
53764
- const actual = parseVersion(version);
53765
- const minimum = parseVersion(match[1]);
53766
- if (actual === void 0 || minimum === void 0) return false;
53767
- if (match[2] === void 0) return compareVersions(actual, minimum) >= 0;
53768
- const maximum = parseVersion(match[2]);
53769
- if (maximum === void 0) return false;
53770
- return compareVersions(actual, minimum) >= 0 && compareVersions(actual, maximum) <= 0;
53771
- }
53772
- function parseVersion(value) {
53773
- const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(value);
53774
- if (match === null) return void 0;
53775
- return {
53776
- major: Number(match[1]),
53777
- minor: Number(match[2]),
53778
- patch: Number(match[3]),
53779
- pre: match[4] === void 0 ? [] : match[4].split(".").map((part) => /^\d+$/u.test(part) ? Number(part) : part)
53780
- };
53781
- }
53782
- function compareVersions(left, right) {
53783
- for (const key of [
53784
- "major",
53785
- "minor",
53786
- "patch"
53787
- ]) if (left[key] !== right[key]) return left[key] - right[key];
53788
- if (left.pre.length === 0 && right.pre.length > 0) return 1;
53789
- if (left.pre.length > 0 && right.pre.length === 0) return -1;
53790
- for (let index = 0; index < Math.max(left.pre.length, right.pre.length); index += 1) {
53791
- const a = left.pre[index];
53792
- const b = right.pre[index];
53793
- if (a === void 0) return -1;
53794
- if (b === void 0) return 1;
53795
- if (a === b) continue;
53796
- if (typeof a === "number" && typeof b === "string") return -1;
53797
- if (typeof a === "string" && typeof b === "number") return 1;
53798
- return a < b ? -1 : 1;
53799
- }
53800
- return 0;
53801
- }
53802
- function errorMessage$1(error) {
53803
- return error instanceof Error ? error.message : String(error);
53804
- }
53805
- //#endregion
53806
- //#region src/dsh-capabilities/client/terminal-sharing-adapter.ts
53807
- /** DSH 版本差异只在本适配器探测,终端业务不读取宿主私有编辑器。 */
53808
- function supportsTerminalSharing(context) {
53809
- return typeof service(context, "sessions")?.scope === "function" && typeof service(context, "conversation")?.input?.for === "function" && typeof service(context, "uiWorkspace")?.openSession === "function";
53810
- }
53811
- function createTerminalSharingBridge(context) {
53812
- if (!supportsTerminalSharing(context)) throw new Error("当前 DSH 缺少会话草稿分享能力");
53813
- const sessions = service(context, "sessions");
53814
- const conversation = service(context, "conversation");
53815
- const navigation = service(context, "uiWorkspace");
53816
- const workspaceSnapshot = () => service(context, "workspaces")?.list?.getSnapshot();
53131
+ function createTerminalSharingBridge(context) {
53132
+ if (!supportsTerminalSharing(context)) throw new Error("当前 DSH 缺少会话草稿分享能力");
53133
+ const sessions = service(context, "sessions");
53134
+ const conversation = service(context, "conversation");
53135
+ const navigation = service(context, "uiWorkspace");
53136
+ const workspaceSnapshot = () => service(context, "workspaces")?.list?.getSnapshot();
53817
53137
  return {
53818
53138
  async targets(signal, query) {
53819
53139
  const rows = /* @__PURE__ */ new Map();
@@ -54098,6 +53418,35 @@ ${scope} [data-dockkit-strip-tabs] {
54098
53418
  }
54099
53419
  //#endregion
54100
53420
  //#region src/dsh-capabilities/client/slot-presentation-mirror.ts
53421
+ /** Follow a native entry that may load after its slot or be replaced during reload. */
53422
+ function followPresentationEntry(slots, name, matches, mount) {
53423
+ return slots.inject(name, () => {
53424
+ let native;
53425
+ let remove;
53426
+ let disposed = false;
53427
+ const reconcile = () => {
53428
+ if (disposed || native !== void 0 && slots.entries(name).includes(native)) return;
53429
+ remove?.();
53430
+ remove = void 0;
53431
+ native = slots.entries(name).find(matches);
53432
+ if (native !== void 0) remove = mount(native);
53433
+ };
53434
+ const unsubscribe = slots.subscribe(name, reconcile);
53435
+ const dispose = () => {
53436
+ disposed = true;
53437
+ unsubscribe();
53438
+ remove?.();
53439
+ remove = void 0;
53440
+ };
53441
+ try {
53442
+ reconcile();
53443
+ } catch (error) {
53444
+ dispose();
53445
+ throw error;
53446
+ }
53447
+ return dispose;
53448
+ });
53449
+ }
54101
53450
  /** Render existing actions in an owned slot without redeclaring or mutating native slots. */
54102
53451
  function mirrorPresentationSlot(slots, source, target, element) {
54103
53452
  return slots.inject(source, () => {
@@ -54176,9 +53525,7 @@ ${scope} [data-dockkit-strip-tabs] {
54176
53525
  },
54177
53526
  questions(sessionId, component, element) {
54178
53527
  const actionSlot = `codingns.translation.plan-actions.${encodeURIComponent(sessionId)}`;
54179
- return slots.inject("conversation.composer", () => {
54180
- const native = slots.entries("conversation.composer").find((entry) => entry.children?.["conversation.plan-review.actions"] !== void 0);
54181
- if (native === void 0 || typeof native.select !== "function") return () => void 0;
53528
+ return followPresentationEntry(slots, "conversation.composer", (entry) => entry.children?.["conversation.plan-review.actions"] !== void 0 && typeof entry.select === "function", (native) => {
54182
53529
  const select = native.select;
54183
53530
  const removeQuestion = slots.register({
54184
53531
  name: "conversation.composer",
@@ -54215,9 +53562,7 @@ ${scope} [data-dockkit-strip-tabs] {
54215
53562
  });
54216
53563
  },
54217
53564
  todos(render, element) {
54218
- return slots.inject("conversation.input.dock", () => {
54219
- const native = slots.entries("conversation.input.dock").find((entry) => entry.options.id === "todo");
54220
- if (native === void 0) return () => void 0;
53565
+ return followPresentationEntry(slots, "conversation.input.dock", (entry) => entry.options.id === "todo", (native) => {
54221
53566
  return slots.register({
54222
53567
  name: "conversation.input.dock",
54223
53568
  id: "todo",
@@ -54236,9 +53581,7 @@ ${scope} [data-dockkit-strip-tabs] {
54236
53581
  });
54237
53582
  },
54238
53583
  questionHistory(render, element) {
54239
- return slots.inject("tool.call.toolview", () => {
54240
- const native = slots.entries("tool.call.toolview").find((entry) => entry.options.key === "ask_user_question");
54241
- if (native === void 0) return () => void 0;
53584
+ return followPresentationEntry(slots, "tool.call.toolview", (entry) => entry.options.key === "ask_user_question", (native) => {
54242
53585
  return slots.register({
54243
53586
  name: "tool.call.toolview",
54244
53587
  key: "ask_user_question",
@@ -54299,6 +53642,115 @@ ${scope} [data-dockkit-strip-tabs] {
54299
53642
  ].includes(item.status ?? "");
54300
53643
  }
54301
53644
  //#endregion
53645
+ //#region src/dsh-capabilities/client/message-presentation-adapter.ts
53646
+ function slotsOf(context) {
53647
+ return context?.slots;
53648
+ }
53649
+ function supportsLegacyMessagePresentation(context, exports) {
53650
+ const slots = slotsOf(context);
53651
+ return typeof slots?.inject === "function" && typeof slots.register === "function" && typeof exports?.projectUserText === "function";
53652
+ }
53653
+ function supportsFactoryMessagePresentation(context) {
53654
+ const slots = slotsOf(context);
53655
+ return typeof slots?.inject === "function" && typeof slots.register === "function" && typeof slots.registerFactory === "function";
53656
+ }
53657
+ function createLegacyMessagePresentation(exports) {
53658
+ return {
53659
+ kind: "legacy",
53660
+ mount: (register) => register(),
53661
+ projectText: exports.projectUserText,
53662
+ userContent: () => null,
53663
+ images: (owner, props) => owner.renderMessageImages(props)
53664
+ };
53665
+ }
53666
+ /** Native factories preserve the host's text transforms, reference actions and image authorization. */
53667
+ function createFactoryMessagePresentation(context) {
53668
+ const slots = slotsOf(context);
53669
+ return {
53670
+ kind: "factory",
53671
+ mount: (register) => slots.inject("conversation.user.text.node", () => slots.inject("conversation.chat.user.images", register)),
53672
+ projectText: () => null,
53673
+ userContent: (owner, content, facts) => owner.renderFactorySlot("conversation.chat.user.content", {
53674
+ content,
53675
+ facts,
53676
+ loadImage: owner.loadImage,
53677
+ interactive: true
53678
+ }),
53679
+ images: (owner, props) => owner.renderFactorySlot("conversation.images.content", {
53680
+ ...props,
53681
+ loadImage: owner.loadImage
53682
+ })
53683
+ };
53684
+ }
53685
+ //#endregion
53686
+ //#region src/dsh-capabilities/host/session-model-selection-adapter.ts
53687
+ function selectionOwner(controller) {
53688
+ const owner = controller?.agents;
53689
+ return typeof owner?.selectionFor === "function" ? owner : void 0;
53690
+ }
53691
+ function supportsSessionModelSelection(controller) {
53692
+ return selectionOwner(controller) !== void 0;
53693
+ }
53694
+ /**
53695
+ * DSH's prompt admission reads selectionFor().current before agent/request.
53696
+ * Its public selectModel() also persists the global default and requires a
53697
+ * catalog entry, so external routes must not use it for this session-local view.
53698
+ * Keep this internal accessor behind the bounded, structurally probed route.
53699
+ */
53700
+ function createSessionModelSelectionAdapter(controller) {
53701
+ const owner = selectionOwner(controller);
53702
+ return { install(resolve) {
53703
+ const original = owner.selectionFor;
53704
+ const ownDescriptor = Object.getOwnPropertyDescriptor(owner, "selectionFor");
53705
+ const selectionFor = function(agent) {
53706
+ const selection = original.call(this, agent);
53707
+ const external = resolve(agent.id);
53708
+ if (external === void 0) return selection;
53709
+ return new Proxy(selection, { get(target, key, receiver) {
53710
+ return key === "current" ? external : Reflect.get(target, key, receiver);
53711
+ } });
53712
+ };
53713
+ owner.selectionFor = selectionFor;
53714
+ return () => {
53715
+ if (owner.selectionFor !== selectionFor) return;
53716
+ if (ownDescriptor !== void 0) Object.defineProperty(owner, "selectionFor", ownDescriptor);
53717
+ else Reflect.deleteProperty(owner, "selectionFor");
53718
+ };
53719
+ } };
53720
+ }
53721
+ //#endregion
53722
+ //#region src/dsh-capabilities/host/session-prompt-adapter.ts
53723
+ function supportsSessionPromptAssembly(value) {
53724
+ const ctx = value;
53725
+ const prompt = ctx?.get?.("systemPrompt") ?? ctx?.systemPrompt;
53726
+ return typeof ctx?.on === "function" && typeof prompt?.assemble === "function";
53727
+ }
53728
+ /** Keep DSH's agent identity and scope shape inside the versioned boundary. */
53729
+ function sessionPromptScope(agent, signal) {
53730
+ const header = agent?.session?.header;
53731
+ return {
53732
+ sessionId: typeof agent?.id === "string" ? agent.id : typeof header?.id === "string" ? header.id : "",
53733
+ subagent: header?.origin === "subagent" || header?.delegationDepth > 0 || agent?.options?.subagentDepth > 0,
53734
+ literals: [header?.cwd, agent?.cwd].filter((value) => typeof value === "string" && value !== ""),
53735
+ ...signal === void 0 ? {} : { signal }
53736
+ };
53737
+ }
53738
+ function createSessionPromptAdapter(value) {
53739
+ const ctx = value;
53740
+ return { install(transform) {
53741
+ const dispose = ctx.on("system-prompt/assemble", async (_assembly, context, next) => {
53742
+ const assembly = await next();
53743
+ const scope = sessionPromptScope(context?.agent, context?.signal);
53744
+ if (scope.sessionId === "" || scope.subagent || !Array.isArray(assembly?.sections) || !Array.isArray(assembly.tools)) return assembly;
53745
+ return transform(assembly, scope);
53746
+ }, {
53747
+ global: true,
53748
+ prepend: true
53749
+ });
53750
+ return typeof dispose === "function" ? dispose : () => void 0;
53751
+ } };
53752
+ }
53753
+ //#endregion
54302
53754
  //#region src/dsh-capabilities/routes.ts
54303
53755
  /**
54304
53756
  * 注册 Codingns4DSH 当前实际消费的 DSH 服务能力。
@@ -54313,6 +53765,61 @@ ${scope} [data-dockkit-strip-tabs] {
54313
53765
  const range020 = require_native_workspace_store.DSH_COMPATIBILITY;
54314
53766
  const add = (route) => registry.register(route);
54315
53767
  if (runtime === "host") {
53768
+ add({
53769
+ id: "session-prompt-assembly-021",
53770
+ capability: "session.prompt-assembly",
53771
+ supportedDsh: ">=0.2.1-alpha.3 <=0.2.1-alpha.3",
53772
+ runtime,
53773
+ priority: 10,
53774
+ status: "supported",
53775
+ introducedIn: "0.2.1-alpha.3",
53776
+ detect: supportsSessionPromptAssembly,
53777
+ create: createSessionPromptAdapter
53778
+ });
53779
+ add({
53780
+ id: "session-external-model-selection-021",
53781
+ capability: "session.external-model-selection",
53782
+ supportedDsh: ">=0.2.1-alpha.3 <=0.2.1-alpha.3",
53783
+ runtime,
53784
+ priority: 10,
53785
+ status: "supported",
53786
+ introducedIn: "0.2.1-alpha.3",
53787
+ detect: (ctx) => supportsSessionModelSelection(read(ctx, "sessionController")),
53788
+ create: (ctx) => createSessionModelSelectionAdapter(read(ctx, "sessionController"))
53789
+ });
53790
+ add({
53791
+ id: "session-activation-020",
53792
+ capability: "session.activation",
53793
+ supportedDsh: ">=0.2.0-rc.2 <=0.2.1-alpha.2",
53794
+ runtime,
53795
+ priority: 10,
53796
+ status: "supported",
53797
+ introducedIn: "0.2.0-rc.2",
53798
+ detect: (ctx) => hasMethods(read(ctx, "sessionController"), ["create"]),
53799
+ create: (ctx) => read(ctx, "sessionController")
53800
+ });
53801
+ add({
53802
+ id: "session-activation-021",
53803
+ capability: "session.activation",
53804
+ supportedDsh: ">=0.2.1-alpha.3 <=0.2.1-alpha.3",
53805
+ runtime,
53806
+ priority: 10,
53807
+ status: "supported",
53808
+ introducedIn: "0.2.1-alpha.3",
53809
+ detect: (ctx) => hasMethods(read(ctx, "sessionController"), ["create", "resolveAgent"]),
53810
+ create: (ctx) => read(ctx, "sessionController")
53811
+ });
53812
+ for (const capability of ["connection.peer", "connection.uplink"]) add({
53813
+ id: `${capability}-021`,
53814
+ capability,
53815
+ supportedDsh: ">=0.2.1-alpha.3 <=0.2.1-alpha.3",
53816
+ runtime,
53817
+ priority: 40,
53818
+ status: "supported",
53819
+ introducedIn: "0.2.1-alpha.3",
53820
+ detect: (ctx) => hasMethods(read(ctx, "connection"), ["admit", "createPeer"]) && read(ctx, "connection.browserPeer") !== void 0,
53821
+ create: (ctx) => read(ctx, "connection")
53822
+ });
54316
53823
  add({
54317
53824
  id: "assistant-agent-021",
54318
53825
  capability: "assistant.agent",
@@ -54398,6 +53905,28 @@ ${scope} [data-dockkit-strip-tabs] {
54398
53905
  addDsh020HostRoutes(add, range020);
54399
53906
  addPeerHostHostRoutes(add);
54400
53907
  } else {
53908
+ add({
53909
+ id: "message-presentation-020",
53910
+ capability: "conversation.message-presentation",
53911
+ supportedDsh: ">=0.2.0-rc.2 <=0.2.1-alpha.2",
53912
+ runtime,
53913
+ priority: 10,
53914
+ status: "supported",
53915
+ introducedIn: "0.2.0-rc.2",
53916
+ detect: (ctx) => supportsLegacyMessagePresentation({ slots: read(ctx, "slots") }, facts.primitives),
53917
+ create: () => createLegacyMessagePresentation(facts.primitives)
53918
+ });
53919
+ add({
53920
+ id: "message-presentation-021",
53921
+ capability: "conversation.message-presentation",
53922
+ supportedDsh: ">=0.2.1-alpha.3 <=0.2.1-alpha.3",
53923
+ runtime,
53924
+ priority: 10,
53925
+ status: "supported",
53926
+ introducedIn: "0.2.1-alpha.3",
53927
+ detect: (ctx) => supportsFactoryMessagePresentation({ slots: read(ctx, "slots") }),
53928
+ create: createFactoryMessagePresentation
53929
+ });
54401
53930
  add({
54402
53931
  id: "settings-scope",
54403
53932
  capability: "settings.store",
@@ -54489,12 +54018,12 @@ ${scope} [data-dockkit-strip-tabs] {
54489
54018
  add({
54490
54019
  id: "interaction-presentation-021",
54491
54020
  capability: "conversation.interaction-translation",
54492
- supportedDsh: ">=0.2.1-alpha.1 <=0.2.1-alpha.2",
54021
+ supportedDsh: range020,
54493
54022
  runtime,
54494
54023
  priority: 10,
54495
54024
  status: "supported",
54496
- introducedIn: "0.2.1-alpha.1",
54497
- detect: supportsInteractionPresentation,
54025
+ introducedIn: "0.2.0-rc.2",
54026
+ detect: (ctx) => supportsInteractionPresentation({ slots: read(ctx, "slots") }),
54498
54027
  create: createInteractionPresentationBridge
54499
54028
  });
54500
54029
  addDsh020ClientRoutes(add, range020, facts);
@@ -54573,7 +54102,7 @@ ${scope} [data-dockkit-strip-tabs] {
54573
54102
  add({
54574
54103
  id: "connection-peer-admission-020",
54575
54104
  capability: "connection.peer",
54576
- supportedDsh,
54105
+ supportedDsh: ">=0.2.0-rc.2 <=0.2.1-alpha.2",
54577
54106
  runtime: "host",
54578
54107
  priority: 30,
54579
54108
  status: "supported",
@@ -54595,7 +54124,7 @@ ${scope} [data-dockkit-strip-tabs] {
54595
54124
  add({
54596
54125
  id: "connection-rpc-uplink-020",
54597
54126
  capability: "connection.uplink",
54598
- supportedDsh,
54127
+ supportedDsh: ">=0.2.0-rc.2 <=0.2.1-alpha.2",
54599
54128
  runtime: "host",
54600
54129
  priority: 10,
54601
54130
  status: "supported",
@@ -54711,7 +54240,7 @@ ${scope} [data-dockkit-strip-tabs] {
54711
54240
  add({
54712
54241
  id: "conversation-draft-share-021",
54713
54242
  capability: "conversation.draft-share",
54714
- supportedDsh: ">=0.2.1-alpha.1 <=0.2.1-alpha.2",
54243
+ supportedDsh: ">=0.2.1-alpha.1 <=0.2.1-alpha.3",
54715
54244
  runtime: "client",
54716
54245
  priority: 30,
54717
54246
  status: "supported",
@@ -54851,161 +54380,1395 @@ ${scope} [data-dockkit-strip-tabs] {
54851
54380
  detect: (ctx) => read(ctx, "modules.version") === "client",
54852
54381
  create: (ctx) => read(ctx, "modules")
54853
54382
  });
54854
- add({
54855
- id: "layout-columns-020",
54856
- capability: "layout.columns",
54857
- supportedDsh,
54858
- runtime: "client",
54859
- priority: 30,
54860
- status: "supported",
54861
- introducedIn: "0.2.0-rc.1",
54862
- detect: (ctx) => typeof read(ctx, "layout.toggleSidebar") === "function",
54863
- create: (ctx) => read(ctx, "layout")
54383
+ add({
54384
+ id: "layout-columns-020",
54385
+ capability: "layout.columns",
54386
+ supportedDsh,
54387
+ runtime: "client",
54388
+ priority: 30,
54389
+ status: "supported",
54390
+ introducedIn: "0.2.0-rc.1",
54391
+ detect: (ctx) => typeof read(ctx, "layout.toggleSidebar") === "function",
54392
+ create: (ctx) => read(ctx, "layout")
54393
+ });
54394
+ add({
54395
+ id: "sidebar-right-expand-020",
54396
+ capability: "sidebar.right.expand",
54397
+ supportedDsh,
54398
+ runtime: "client",
54399
+ priority: 30,
54400
+ status: "supported",
54401
+ introducedIn: "0.2.0-rc.1",
54402
+ detect: (ctx) => hasMethods(read(ctx, "sidebarRight"), ["isExpanded", "toggleExpanded"]),
54403
+ create: (ctx) => read(ctx, "sidebarRight")
54404
+ });
54405
+ }
54406
+ /**
54407
+ * 读取探测上下文里的服务或结构事实。
54408
+ *
54409
+ * Cordis 的 Context 只在调用方 fiber 的 inject 链(或祖先 fiber 提供的服务)里
54410
+ * 解析属性;直接读未注入的服务会抛 `cannot get property "x" without inject`,
54411
+ * 把 `a || b` 形式的探测短路成失败。因此这里统一先走 `ctx.get(...)`(Cordis 提供
54412
+ * 的免 inject 读取),再回退到普通属性读取,让探测只依据服务形状,不受消费方
54413
+ * inject 列表影响。
54414
+ */
54415
+ function read(context, path) {
54416
+ const [head, ...rest] = path.split(".");
54417
+ if (head === void 0) return void 0;
54418
+ let value = readKey(context, head);
54419
+ for (const key of rest) value = readProperty(value, key);
54420
+ return value;
54421
+ }
54422
+ /** 读取上下文上的服务(优先 `ctx.get`)或直接挂在上下文上的事实对象。 */
54423
+ function readKey(context, key) {
54424
+ if (typeof context !== "object" || context === null) return void 0;
54425
+ const getter = readProperty(context, "get");
54426
+ if (typeof getter === "function") try {
54427
+ const value = getter.call(context, key);
54428
+ if (value !== void 0) return value;
54429
+ } catch {}
54430
+ return readProperty(context, key);
54431
+ }
54432
+ /** 读取对象属性;Cordis 代理对未注入的服务会抛错,统一按缺失处理。 */
54433
+ function readProperty(target, key) {
54434
+ if (typeof target !== "object" || target === null) return void 0;
54435
+ try {
54436
+ return Reflect.get(target, key);
54437
+ } catch {
54438
+ return;
54439
+ }
54440
+ }
54441
+ function hasMethods(value, methods) {
54442
+ return typeof value === "object" && value !== null && methods.every((method) => typeof Reflect.get(value, method) === "function");
54443
+ }
54444
+ function hasAny(value, keys) {
54445
+ return typeof value === "object" && value !== null && keys.some((key) => Reflect.get(value, key) !== void 0);
54446
+ }
54447
+ /** PeerHost Host 能力只接受显式注入的适配器,避免把普通 DSH 服务误报为已实现。 */
54448
+ function addPeerHostHostRoutes(add) {
54449
+ addPeerHostRoute(add, "peer-host.store", "peer-host-store", "peerHostStore");
54450
+ addPeerHostRoute(add, "peer-host.handshake", "peer-host-handshake", "peerHostHandshake");
54451
+ addPeerHostRoute(add, "peer-host.http-proxy", "peer-host-http-proxy", "peerHostHttpProxy");
54452
+ addPeerHostRoute(add, "peer-host.ws-proxy", "peer-host-ws-proxy", "peerHostWsProxy");
54453
+ addPeerHostRoute(add, "peer-host.aggregate", "peer-host-aggregate", "peerHostAggregate");
54454
+ addPeerHostRoute(add, "peer-host.aggregated-transport", "peer-host-aggregated-transport", "peerHostAggregatedTransport");
54455
+ addPeerHostRoute(add, "peer-host.target-capabilities", "peer-host-target-capabilities", "peerHostTargetCapabilities");
54456
+ addPeerHostRoute(add, "peer-host.local-plugin-baseline", "peer-host-local-plugin-baseline", "peerHostLocalPluginBaseline");
54457
+ addPeerHostRoute(add, "peer-host.relay-route", "peer-host-relay-route", "peerHostRelayRoute");
54458
+ addPeerHostRoute(add, "peer-host.store", "peer-host-store-020", "peerHostStore", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54459
+ addPeerHostRoute(add, "peer-host.handshake", "peer-host-handshake-020", "peerHostHandshake", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54460
+ addPeerHostRoute(add, "peer-host.http-proxy", "peer-host-http-proxy-020", "peerHostHttpProxy", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54461
+ addPeerHostRoute(add, "peer-host.ws-proxy", "peer-host-ws-proxy-020", "peerHostWsProxy", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54462
+ addPeerHostRoute(add, "peer-host.aggregate", "peer-host-aggregate-020", "peerHostAggregate", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54463
+ addPeerHostRoute(add, "peer-host.aggregated-transport", "peer-host-aggregated-transport-020", "peerHostAggregatedTransport", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54464
+ addPeerHostRoute(add, "peer-host.target-capabilities", "peer-host-target-capabilities-020", "peerHostTargetCapabilities", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54465
+ addPeerHostRoute(add, "peer-host.local-plugin-baseline", "peer-host-local-plugin-baseline-020", "peerHostLocalPluginBaseline", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54466
+ addPeerHostRoute(add, "peer-host.relay-route", "peer-host-relay-route-020", "peerHostRelayRoute", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54467
+ }
54468
+ /**
54469
+ * PeerHost Client 导航能力由独立 adapter 注入;未注入时由 Feature 诊断降级。
54470
+ *
54471
+ * `peer-host.client-preboot-transport` 表示"页面在 DSH Connection 之前已可被聚合
54472
+ * Transport 包装"。它不再等待官方 Provider 适配器,而是由插件自带的启动页 shim
54473
+ * 提供:Web 与 Desktop 都注入同一个 shim,Desktop 用访问器接管运行时赋值。探测
54474
+ * 只读 shim 状态,`external`(Transport 形状未知)时判为不可用,由 Feature 按
54475
+ * "能力缺失只影响该模块"停用 PeerHost,而不是提示用户刷新。
54476
+ */
54477
+ function addPeerHostClientRoutes(add) {
54478
+ addPeerHostRoute(add, "peer-host.native-navigation", "peer-host-native-navigation-legacy", "peerHostNativeNavigation", ">=0.1.5-rc.3 <=0.1.6", "deprecated");
54479
+ addPeerHostRoute(add, "peer-host.native-navigation", "peer-host-native-navigation-modern", "peerHostNativeNavigation", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", 20);
54480
+ addPeerHostRoute(add, "peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback", "peerHostRemoteWebContextFallback");
54481
+ addPeerHostRoute(add, "peer-host.native-navigation", "peer-host-native-navigation-020", "peerHostNativeNavigation", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54482
+ addPeerHostRoute(add, "peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback-020", "peerHostRemoteWebContextFallback", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54483
+ add({
54484
+ id: "peer-host-client-preboot-transport-020",
54485
+ capability: "peer-host.client-preboot-transport",
54486
+ supportedDsh: require_native_workspace_store.DSH_COMPATIBILITY,
54487
+ runtime: "client",
54488
+ priority: 40,
54489
+ status: "supported",
54490
+ introducedIn: "0.2.0-rc.2",
54491
+ detect: () => isPeerHostPrebootShimWrappable(),
54492
+ create: () => readPeerHostPrebootShim()
54493
+ });
54494
+ }
54495
+ /**
54496
+ * shim 已安装且不是"结构不支持"时,页面 Transport 可被聚合层包装。
54497
+ *
54498
+ * 探测只读启动页已经写入的全局状态:`not-installed`(脚本未注入)与 `external`
54499
+ * (Transport 形状未知)都判为不可用,让 Feature 按"能力缺失只影响该模块"停用
54500
+ * PeerHost,而不是提示用户刷新。
54501
+ */
54502
+ function isPeerHostPrebootShimWrappable() {
54503
+ const state = readPeerHostPrebootShimState();
54504
+ return state !== "not-installed" && state !== "external";
54505
+ }
54506
+ function readPeerHostPrebootShimState() {
54507
+ const shim = readPeerHostPrebootShim();
54508
+ if (shim === void 0) return "not-installed";
54509
+ try {
54510
+ return typeof shim.getState === "function" ? String(shim.getState()) : "installed";
54511
+ } catch {
54512
+ return "not-installed";
54513
+ }
54514
+ }
54515
+ function readPeerHostPrebootShim() {
54516
+ try {
54517
+ return globalThis[DSH_PEER_HOST_PREBOOT_SHIM_GLOBAL];
54518
+ } catch {
54519
+ return;
54520
+ }
54521
+ }
54522
+ function addPeerHostRoute(add, capability, id, field, supportedDsh = ">=0.1.5-rc.3 <=0.1.7-rc.2", status = "supported", priority = 10) {
54523
+ add({
54524
+ id,
54525
+ capability,
54526
+ supportedDsh,
54527
+ runtime: capability === "peer-host.native-navigation" || capability === "peer-host.remote-web-context-fallback" || capability === "peer-host.client-preboot-transport" ? "client" : "host",
54528
+ priority,
54529
+ status,
54530
+ introducedIn: "0.1.5-rc.3",
54531
+ detect: (context) => readPeerHostAdapter(context, field) !== void 0,
54532
+ create: (context) => readPeerHostAdapter(context, field)
54533
+ });
54534
+ }
54535
+ function readPeerHostAdapter(context, field) {
54536
+ if (Array.isArray(context)) return void 0;
54537
+ return readKey(context, field);
54538
+ }
54539
+ //#endregion
54540
+ //#region src/shared/translation-indicator.ts
54541
+ const TRANSLATION_GLYPH_PATHS = ["M3.5 5.5h10M8.5 3.5v2M12.5 5.5c0 4.4-3.3 7.2-8 9", "M5.5 8.5c1.4 2 3.4 3.7 6 4.8M14.5 19.5l3-8 3 8M15.7 17h3.6"];
54542
+ const TRANSLATION_STATUS_BADGE_STYLE = {
54543
+ position: "absolute",
54544
+ top: "1px",
54545
+ right: "1px",
54546
+ display: "grid",
54547
+ placeItems: "center",
54548
+ width: "10px",
54549
+ height: "10px",
54550
+ zIndex: "1",
54551
+ boxSizing: "border-box",
54552
+ border: "1.5px solid var(--dsw-alias-bg-base, Canvas)",
54553
+ borderRadius: "50%",
54554
+ color: "#fff",
54555
+ fontSize: "6px",
54556
+ fontWeight: "700",
54557
+ lineHeight: "1"
54558
+ };
54559
+ const TRANSLATION_PENDING_BADGE_STYLE = {
54560
+ border: "1.5px solid var(--dsw-alias-button-info-fill, #1677ff)",
54561
+ borderTopColor: "transparent",
54562
+ background: "transparent"
54563
+ };
54564
+ //#endregion
54565
+ //#region src/client/session-translation-pending-dom.ts
54566
+ /** Pending DSH bubbles and queue previews have no renderer slot. */
54567
+ function watchPendingTranslationTargets(anchor, onChange) {
54568
+ const root = anchor.closest("[data-conversation-session]");
54569
+ const Observer = anchor.ownerDocument.defaultView?.MutationObserver;
54570
+ if (root === null || Observer === void 0) return () => void 0;
54571
+ const targets = /* @__PURE__ */ new Map();
54572
+ let nextKey = 0;
54573
+ const scan = () => {
54574
+ observer.disconnect();
54575
+ let changed = false;
54576
+ const rows = new Set(root.querySelectorAll("[data-submission-echo]"));
54577
+ for (const [row, target] of targets) {
54578
+ if (rows.has(row) && root.contains(target.container)) continue;
54579
+ target.container.remove();
54580
+ targets.delete(row);
54581
+ changed = true;
54582
+ }
54583
+ for (const row of rows) {
54584
+ if (row.closest("[data-conversation-session]") !== root) continue;
54585
+ const original = (row.querySelector("[class*=\"bubble\"]") ?? row.querySelector("[class*=\"preview\"]"))?.textContent ?? "";
54586
+ const actions = row.querySelector("[data-clock=\"start\"]") ?? row.querySelector("[class*=\"actions\"]") ?? row;
54587
+ if (original.trim() === "") continue;
54588
+ const existing = targets.get(row);
54589
+ if (existing !== void 0) {
54590
+ if (existing.original !== original) {
54591
+ targets.set(row, {
54592
+ ...existing,
54593
+ original
54594
+ });
54595
+ changed = true;
54596
+ }
54597
+ continue;
54598
+ }
54599
+ const container = anchor.ownerDocument.createElement("span");
54600
+ container.dataset.codingnsPendingTranslation = "";
54601
+ container.style.display = "inline-flex";
54602
+ let before = actions.querySelector("button");
54603
+ while (before !== null && before.parentElement !== actions) before = before.parentElement;
54604
+ actions.insertBefore(container, before);
54605
+ targets.set(row, {
54606
+ key: nextKey++,
54607
+ container,
54608
+ original
54609
+ });
54610
+ changed = true;
54611
+ }
54612
+ if (changed) onChange([...targets.values()]);
54613
+ observer.observe(root, {
54614
+ childList: true,
54615
+ subtree: true,
54616
+ characterData: true
54617
+ });
54618
+ };
54619
+ const observer = new Observer(scan);
54620
+ scan();
54621
+ return () => {
54622
+ observer.disconnect();
54623
+ for (const target of targets.values()) target.container.remove();
54624
+ targets.clear();
54625
+ };
54626
+ }
54627
+ //#endregion
54628
+ //#region src/client/session-translation-retry.ts
54629
+ const stores = /* @__PURE__ */ new WeakMap();
54630
+ /** Share a display result between the reply, collapsed reasoning, and its popup. */
54631
+ function useOutputTranslation(props) {
54632
+ const owner = props.services.rpc ?? props.services;
54633
+ const key = JSON.stringify([
54634
+ props.sessionId,
54635
+ props.messageId,
54636
+ props.outputKind,
54637
+ props.record?.original,
54638
+ props.record?.targetLanguage
54639
+ ]);
54640
+ const entry = (0, react.useMemo)(() => {
54641
+ let store = stores.get(owner);
54642
+ if (store === void 0) {
54643
+ store = /* @__PURE__ */ new Map();
54644
+ stores.set(owner, store);
54645
+ }
54646
+ let value = store.get(key);
54647
+ if (value === void 0) {
54648
+ value = {
54649
+ state: { pending: false },
54650
+ listeners: /* @__PURE__ */ new Set()
54651
+ };
54652
+ store.set(key, value);
54653
+ for (const [oldKey, old] of store) {
54654
+ if (store.size <= 256) break;
54655
+ if (oldKey !== key && !old.state.pending && old.listeners.size === 0) store.delete(oldKey);
54656
+ }
54657
+ }
54658
+ return value;
54659
+ }, [owner, key]);
54660
+ const subscription = (0, react.useMemo)(() => ({
54661
+ subscribe(listener) {
54662
+ entry.listeners.add(listener);
54663
+ return () => {
54664
+ entry.listeners.delete(listener);
54665
+ };
54666
+ },
54667
+ snapshot: () => entry.state
54668
+ }), [entry]);
54669
+ const state = (0, react.useSyncExternalStore)(subscription.subscribe, subscription.snapshot, subscription.snapshot);
54670
+ const publish = (next) => {
54671
+ entry.state = next;
54672
+ for (const listener of entry.listeners) listener();
54673
+ };
54674
+ const record = state.record ?? props.record;
54675
+ const retry = props.sessionId === void 0 || props.outputKind === void 0 || record?.failed !== true ? void 0 : async () => {
54676
+ if (entry.state.pending) return;
54677
+ const controller = new AbortController();
54678
+ entry.controller = controller;
54679
+ publish({
54680
+ record,
54681
+ pending: true
54682
+ });
54683
+ try {
54684
+ const result = await require_model_catalog_cache.callCliRpc(props.services.rpc, "translation/retry-output", {
54685
+ sessionId: props.sessionId,
54686
+ original: record.original,
54687
+ outputKind: props.outputKind
54688
+ }, AbortSignal.any([controller.signal, AbortSignal.timeout(18e4)]));
54689
+ if (!controller.signal.aborted) publish({
54690
+ record: result,
54691
+ pending: false
54692
+ });
54693
+ } catch {
54694
+ if (!controller.signal.aborted) publish({
54695
+ record,
54696
+ pending: false
54697
+ });
54698
+ } finally {
54699
+ if (entry.controller === controller) delete entry.controller;
54700
+ }
54701
+ };
54702
+ return {
54703
+ record,
54704
+ pending: state.pending,
54705
+ retry
54706
+ };
54707
+ }
54708
+ function clearOutputTranslationRetries(services) {
54709
+ const owner = services.rpc ?? services;
54710
+ const store = stores.get(owner);
54711
+ for (const entry of store?.values() ?? []) entry.controller?.abort();
54712
+ stores.delete(owner);
54713
+ }
54714
+ //#endregion
54715
+ //#region src/client/session-translation-chat.ts
54716
+ /**
54717
+ * 把翻译状态和查看原文的入口放回对应消息块,不占用 AI 回复底部的统一操作栏。
54718
+ */
54719
+ function TranslationAction(props) {
54720
+ const [open, setOpen] = (0, react.useState)(props.inputFailure !== void 0);
54721
+ const output = useOutputTranslation({
54722
+ ...props,
54723
+ record: props.inputFailure?.record ?? props.record
54724
+ });
54725
+ const [deciding, setDeciding] = (0, react.useState)(false);
54726
+ const decidingRef = (0, react.useRef)(false);
54727
+ const [decisionError, setDecisionError] = (0, react.useState)(false);
54728
+ (0, react.useEffect)(() => {
54729
+ if (props.inputFailure !== void 0) setOpen(true);
54730
+ setDecisionError(false);
54731
+ }, [props.inputFailure?.id]);
54732
+ const rootRef = (0, react.useRef)(null);
54733
+ const buttonRef = (0, react.useRef)(null);
54734
+ const popupRef = (0, react.useRef)(null);
54735
+ const [popupPosition, setPopupPosition] = (0, react.useState)(null);
54736
+ useDismissOnOutsidePointer(rootRef, open, () => setOpen(false), { portal: popupRef });
54737
+ (0, react.useLayoutEffect)(() => {
54738
+ if (!open || typeof window === "undefined") {
54739
+ setPopupPosition(null);
54740
+ return;
54741
+ }
54742
+ const updatePosition = () => {
54743
+ const button = buttonRef.current;
54744
+ if (button === null) return;
54745
+ const rect = button.getBoundingClientRect();
54746
+ const edge = 12;
54747
+ const gap = 8;
54748
+ const width = Math.max(1, Math.min(420, window.innerWidth - 24));
54749
+ const availableAbove = Math.max(0, rect.top - gap - edge);
54750
+ const availableBelow = Math.max(0, window.innerHeight - rect.bottom - gap - edge);
54751
+ const preferredHeight = Math.min(440, window.innerHeight * .65);
54752
+ const placement = availableAbove >= preferredHeight || availableBelow < preferredHeight && availableAbove > availableBelow ? "above" : "below";
54753
+ const maxHeight = Math.min(preferredHeight, placement === "above" ? availableAbove : availableBelow);
54754
+ const desiredLeft = props.popupAlign === "end" ? rect.right - width : rect.left;
54755
+ const maxLeft = Math.max(edge, window.innerWidth - edge - width);
54756
+ setPopupPosition({
54757
+ left: Math.min(maxLeft, Math.max(edge, desiredLeft)),
54758
+ top: placement === "above" ? rect.top - gap : rect.bottom + gap,
54759
+ width,
54760
+ maxHeight,
54761
+ placement
54762
+ });
54763
+ };
54764
+ updatePosition();
54765
+ window.addEventListener("resize", updatePosition);
54766
+ window.addEventListener("scroll", updatePosition, true);
54767
+ return () => {
54768
+ window.removeEventListener("resize", updatePosition);
54769
+ window.removeEventListener("scroll", updatePosition, true);
54770
+ };
54771
+ }, [open, props.popupAlign]);
54772
+ const record = output.record;
54773
+ const inputFailure = props.inputFailure !== void 0;
54774
+ const detailsTitle = props.translationT(inputFailure ? "translation.inputFailedTitle" : "translation.detailsTitle");
54775
+ const pending = record === void 0 || output.pending;
54776
+ const failed = record?.failed === true;
54777
+ const alreadyTargetLanguage = record?.alreadyTargetLanguage === true;
54778
+ const statusText = pending ? props.translationT("translation.statusTranslating") : failed ? props.translationT("translation.statusFailed") : alreadyTargetLanguage ? props.translationT("translation.statusNotNeeded") : props.translationT("translation.statusTranslated");
54779
+ const statusColor = pending ? require_theme.dshThemeColor.accent : failed ? require_theme.dshThemeColor.error : alreadyTargetLanguage ? require_theme.dshThemeColor.accent : require_theme.dshThemeColor.success;
54780
+ const detailsId = `codingns-translation-details-${safeDomId(props.messageId)}`;
54781
+ const decide = async (choice) => {
54782
+ if (props.inputFailure === void 0 || decidingRef.current) return;
54783
+ decidingRef.current = true;
54784
+ setDeciding(true);
54785
+ setDecisionError(false);
54786
+ try {
54787
+ await require_model_catalog_cache.callCliRpc(props.services.rpc, "translation/resolve", {
54788
+ sessionId: props.inputFailure.sessionId,
54789
+ id: props.inputFailure.id,
54790
+ choice
54791
+ }, AbortSignal.timeout(15e3));
54792
+ props.onDecision?.();
54793
+ } catch {
54794
+ setDecisionError(true);
54795
+ } finally {
54796
+ decidingRef.current = false;
54797
+ setDeciding(false);
54798
+ }
54799
+ };
54800
+ const details = open && popupPosition !== null ? (0, react.createElement)("div", {
54801
+ ref: popupRef,
54802
+ role: "dialog",
54803
+ "aria-label": detailsTitle,
54804
+ id: detailsId,
54805
+ style: {
54806
+ position: "fixed",
54807
+ zIndex: 2147483647,
54808
+ left: popupPosition.left,
54809
+ top: popupPosition.top,
54810
+ width: popupPosition.width,
54811
+ maxHeight: popupPosition.maxHeight,
54812
+ boxSizing: "border-box",
54813
+ ...popupPosition.placement === "above" ? { transform: "translateY(-100%)" } : {},
54814
+ overflow: "auto",
54815
+ padding: "10px 12px",
54816
+ border: `1px solid ${require_theme.dshThemeColor.border}`,
54817
+ borderRadius: 8,
54818
+ color: require_theme.dshThemeColor.labelPrimary,
54819
+ background: require_theme.dshThemeColor.menuBackground,
54820
+ boxShadow: "0 8px 24px color-mix(in srgb, CanvasText 16%, transparent)",
54821
+ fontSize: require_theme.uiFontSize(12),
54822
+ lineHeight: 1.45
54823
+ }
54824
+ }, (0, react.createElement)("div", { style: {
54825
+ display: "flex",
54826
+ justifyContent: "space-between",
54827
+ gap: 10,
54828
+ fontWeight: 600
54829
+ } }, (0, react.createElement)("span", void 0, detailsTitle), inputFailure ? null : (0, react.createElement)("span", {
54830
+ role: "status",
54831
+ "aria-live": "polite",
54832
+ style: {
54833
+ color: statusColor,
54834
+ fontWeight: 400
54835
+ }
54836
+ }, statusText)), inputFailure || record?.sourceLanguage === void 0 ? null : (0, react.createElement)("div", { style: {
54837
+ marginTop: 8,
54838
+ color: require_theme.dshThemeColor.labelSecondary
54839
+ } }, `${props.translationT("translation.detectedLanguage")}: ${props.translationT(`translation.language.${record.sourceLanguage}`)}`), inputFailure ? null : (0, react.createElement)(DetailBlock, {
54840
+ kind: "original",
54841
+ translationT: props.translationT,
54842
+ value: record?.original ?? props.original ?? ""
54843
+ }), pending ? (0, react.createElement)("progress", {
54844
+ "aria-label": statusText,
54845
+ style: {
54846
+ display: "block",
54847
+ width: "100%",
54848
+ height: 4,
54849
+ marginTop: 8,
54850
+ accentColor: require_theme.dshThemeColor.accent
54851
+ }
54852
+ }) : null, pending ? (0, react.createElement)("div", {
54853
+ role: "status",
54854
+ "aria-live": "polite",
54855
+ style: {
54856
+ marginTop: 8,
54857
+ color: require_theme.dshThemeColor.labelSecondary
54858
+ }
54859
+ }, props.translationT("translation.progressHelp")) : props.inputFailure !== void 0 ? null : (0, react.createElement)(DetailBlock, {
54860
+ kind: props.messageRole === "user" ? "sent" : "translated",
54861
+ translationT: props.translationT,
54862
+ value: record.translated
54863
+ }), pending || inputFailure ? null : (0, react.createElement)("div", { style: {
54864
+ marginTop: 8,
54865
+ color: require_theme.dshThemeColor.labelSecondary
54866
+ } }, [
54867
+ `${props.translationT("translation.modelUsed")}: ${alreadyTargetLanguage ? props.translationT("translation.modelNotUsed") : formatModel(record.model, props.translationT)}`,
54868
+ ...record.durationMs === void 0 ? [] : [`${(record.durationMs / 1e3).toFixed(2)} s`],
54869
+ ...record.totalTokens === void 0 ? [] : [`${record.totalTokens} tok`]
54870
+ ].join(" · ")), props.inputFailure === void 0 ? null : (0, react.createElement)("p", { role: "alert" }, props.translationT("translation.inputFailedHelp")), decisionError ? (0, react.createElement)("p", {
54871
+ role: "alert",
54872
+ style: { color: require_theme.dshThemeColor.error }
54873
+ }, props.translationT("translation.decisionFailed")) : null, props.inputFailure !== void 0 ? (0, react.createElement)("div", { style: {
54874
+ display: "flex",
54875
+ flexWrap: "wrap",
54876
+ gap: 8,
54877
+ marginTop: 10
54878
+ } }, ...[
54879
+ "retry",
54880
+ "send",
54881
+ "cancel"
54882
+ ].map((choice) => (0, react.createElement)("button", {
54883
+ key: choice,
54884
+ type: "button",
54885
+ disabled: deciding,
54886
+ onClick: () => {
54887
+ decide(choice);
54888
+ },
54889
+ style: recoveryButtonStyle
54890
+ }, props.translationT(choice === "retry" ? "translation.retry" : choice === "send" ? "translation.sendDirectly" : "translation.cancelSending")))) : output.retry === void 0 ? null : (0, react.createElement)("button", {
54891
+ type: "button",
54892
+ disabled: pending,
54893
+ onClick: () => {
54894
+ output.retry?.();
54895
+ },
54896
+ style: {
54897
+ ...recoveryButtonStyle,
54898
+ marginTop: 10
54899
+ }
54900
+ }, props.translationT("translation.retry"))) : null;
54901
+ const renderedDetails = details === null ? null : typeof document === "undefined" ? details : (0, import_react_dom.createPortal)(details, document.body);
54902
+ return (0, react.createElement)("div", {
54903
+ ref: rootRef,
54904
+ style: {
54905
+ position: "relative",
54906
+ display: "inline-flex",
54907
+ alignItems: "center",
54908
+ verticalAlign: "middle",
54909
+ ...props.inline === true ? { marginInlineStart: 4 } : {}
54910
+ },
54911
+ "data-codingns-translation-action": props.messageId
54912
+ }, (0, react.createElement)("button", {
54913
+ ref: buttonRef,
54914
+ type: "button",
54915
+ title: `${statusText} · ${props.translationT("translation.viewDetails")}`,
54916
+ "aria-label": `${statusText} · ${props.translationT("translation.viewDetails")}`,
54917
+ "aria-expanded": open,
54918
+ "aria-controls": detailsId,
54919
+ onClick: () => setOpen((value) => !value),
54920
+ style: translationButtonStyle
54921
+ }, (0, react.createElement)(TranslationGlyph), (0, react.createElement)("span", {
54922
+ "aria-hidden": true,
54923
+ "data-codingns-translation-pending": pending || void 0,
54924
+ style: {
54925
+ ...TRANSLATION_STATUS_BADGE_STYLE,
54926
+ ...pending ? TRANSLATION_PENDING_BADGE_STYLE : { background: statusColor }
54927
+ }
54928
+ }, pending ? null : failed ? "!" : "✓")), renderedDetails);
54929
+ }
54930
+ const recoveryButtonStyle = {
54931
+ padding: "5px 10px",
54932
+ borderRadius: 6,
54933
+ border: `1px solid ${require_theme.dshThemeColor.border}`,
54934
+ background: require_theme.dshThemeColor.surfaceSubtle,
54935
+ color: require_theme.dshThemeColor.labelPrimary,
54936
+ cursor: "pointer",
54937
+ font: "inherit"
54938
+ };
54939
+ function PendingTranslationActions(props) {
54940
+ const anchorRef = (0, react.useRef)(null);
54941
+ const [targets, setTargets] = (0, react.useState)([]);
54942
+ const [failures, setFailures] = (0, react.useState)([]);
54943
+ const pollingRef = (0, react.useRef)();
54944
+ const enabled = useCliSessionTranslationEnabled(props.sessionId, props.services.rpc);
54945
+ const store = props.services.settings;
54946
+ const settings = (0, react.useSyncExternalStore)(store.subscribe.bind(store), store.getSnapshot.bind(store), store.getSnapshot.bind(store));
54947
+ const subagent = props.useSession?.((state) => state.subagent);
54948
+ const eligible = enabled && settings.value?.sessionTranslation?.inputEnabled !== false && subagent == null && !props.sessionId?.startsWith("codingns-assistant-");
54949
+ (0, react.useEffect)(() => {
54950
+ setFailures([]);
54951
+ if (!eligible || props.sessionId === void 0) return;
54952
+ const polling = startSerialPolling(async (signal) => {
54953
+ const next = await require_model_catalog_cache.callCliRpc(props.services.rpc, "translation/pending", { sessionId: props.sessionId }, signal);
54954
+ if (!signal.aborted && Array.isArray(next)) setFailures((current) => JSON.stringify(current) === JSON.stringify(next) ? current : next);
54955
+ }, 750);
54956
+ pollingRef.current = polling;
54957
+ return () => {
54958
+ polling.dispose();
54959
+ pollingRef.current = void 0;
54960
+ };
54961
+ }, [
54962
+ eligible,
54963
+ props.sessionId,
54964
+ props.services.rpc
54965
+ ]);
54966
+ (0, react.useLayoutEffect)(() => {
54967
+ setTargets([]);
54968
+ if (!eligible || anchorRef.current === null) return void 0;
54969
+ return watchPendingTranslationTargets(anchorRef.current, setTargets);
54970
+ }, [eligible, props.sessionId]);
54971
+ const remaining = [...failures];
54972
+ const actions = targets.map((target) => {
54973
+ const index = remaining.findIndex((failure) => normalizePendingText(failure.record.original) === normalizePendingText(target.original));
54974
+ const failure = index < 0 ? void 0 : remaining.splice(index, 1)[0];
54975
+ return (0, import_react_dom.createPortal)((0, react.createElement)(PendingTranslationAction, {
54976
+ services: props.services,
54977
+ translationT: props.translationT,
54978
+ original: target.original,
54979
+ inputFailure: failure,
54980
+ onDecision: () => {
54981
+ pollingRef.current?.refresh({ afterPending: true });
54982
+ }
54983
+ }), target.container, String(target.key));
54984
+ });
54985
+ return (0, react.createElement)("span", {
54986
+ ref: anchorRef,
54987
+ style: { display: "contents" }
54988
+ }, ...actions, ...remaining.map((failure) => (0, react.createElement)("span", {
54989
+ key: failure.id,
54990
+ style: {
54991
+ display: "inline-flex",
54992
+ alignItems: "center",
54993
+ gap: 8,
54994
+ maxWidth: "100%"
54995
+ }
54996
+ }, (0, react.createElement)("span", { style: {
54997
+ maxWidth: 240,
54998
+ overflow: "hidden",
54999
+ textOverflow: "ellipsis",
55000
+ whiteSpace: "nowrap"
55001
+ } }, failure.record.original), (0, react.createElement)(PendingTranslationAction, {
55002
+ services: props.services,
55003
+ translationT: props.translationT,
55004
+ original: failure.record.original,
55005
+ inputFailure: failure,
55006
+ onDecision: () => {
55007
+ pollingRef.current?.refresh({ afterPending: true });
55008
+ }
55009
+ }))));
55010
+ }
55011
+ function normalizePendingText(value) {
55012
+ return value.replace(/\s+/gu, " ").trim();
55013
+ }
55014
+ function PendingTranslationAction(props) {
55015
+ const id = (0, react.useId)();
55016
+ return (0, react.createElement)(TranslationAction, {
55017
+ ...props,
55018
+ messageId: `pending-${id}`,
55019
+ messageRole: "user",
55020
+ popupAlign: "end"
55021
+ });
55022
+ }
55023
+ function TranslationGlyph() {
55024
+ return (0, react.createElement)("svg", {
55025
+ viewBox: "0 0 24 24",
55026
+ width: 16,
55027
+ height: 16,
55028
+ fill: "none",
55029
+ stroke: "currentColor",
55030
+ strokeWidth: 1.5,
55031
+ strokeLinecap: "round",
55032
+ strokeLinejoin: "round",
55033
+ "aria-hidden": true
55034
+ }, ...TRANSLATION_GLYPH_PATHS.map((d) => (0, react.createElement)("path", {
55035
+ key: d,
55036
+ d
55037
+ })));
55038
+ }
55039
+ const messageActionButtonStyle = {
55040
+ position: "relative",
55041
+ display: "inline-flex",
55042
+ alignItems: "center",
55043
+ justifyContent: "center",
55044
+ width: 28,
55045
+ height: 28,
55046
+ padding: 0,
55047
+ border: 0,
55048
+ borderRadius: "var(--dsw-radius-sm, 6px)",
55049
+ color: require_theme.dshThemeColor.labelTertiary,
55050
+ background: "transparent",
55051
+ cursor: "pointer"
55052
+ };
55053
+ const translationButtonStyle = {
55054
+ ...messageActionButtonStyle,
55055
+ transition: "background-color 100ms ease, color 100ms ease"
55056
+ };
55057
+ const translationDetailTypes = {
55058
+ original: {
55059
+ labelKey: "translation.originalText",
55060
+ color: require_theme.dshThemeColor.labelSecondary
55061
+ },
55062
+ translated: {
55063
+ labelKey: "translation.translatedText",
55064
+ color: require_theme.dshThemeColor.accent
55065
+ },
55066
+ sent: {
55067
+ labelKey: "translation.actualSentText",
55068
+ color: require_theme.dshThemeColor.success
55069
+ }
55070
+ };
55071
+ function DetailBlock({ kind, translationT, value }) {
55072
+ const { labelKey, color } = translationDetailTypes[kind];
55073
+ return (0, react.createElement)("div", { style: { marginTop: 8 } }, (0, react.createElement)("div", { style: {
55074
+ display: "inline-block",
55075
+ maxWidth: "100%",
55076
+ boxSizing: "border-box",
55077
+ marginBottom: 6,
55078
+ padding: "2px 8px",
55079
+ border: `1px solid color-mix(in srgb, ${color} 30%, transparent)`,
55080
+ borderRadius: "var(--dsw-radius-sm, 6px)",
55081
+ color,
55082
+ background: `color-mix(in srgb, ${color} 12%, transparent)`,
55083
+ fontWeight: 600,
55084
+ overflowWrap: "anywhere"
55085
+ } }, translationT(labelKey)), (0, react.createElement)("pre", { style: {
55086
+ margin: 0,
55087
+ color: `color-mix(in srgb, ${color} 45%, ${require_theme.dshThemeColor.labelPrimary})`,
55088
+ whiteSpace: "pre-wrap",
55089
+ overflowWrap: "anywhere",
55090
+ fontFamily: "inherit"
55091
+ } }, value));
55092
+ }
55093
+ /** 按原生 user 节点的结构渲染用户消息;翻译入口只在确实有记录时追加。 */
55094
+ function UserMessageNodeView(props) {
55095
+ const data = props.node.data;
55096
+ const parts = splitUserContent(data.content);
55097
+ const record = readInputRecord({ source: data.source });
55098
+ const translationRecord = record === void 0 ? void 0 : inputRecordForAction(record);
55099
+ const labels = Array.isArray(data.referenceLabels) ? data.referenceLabels.filter((label) => typeof label === "string") : [];
55100
+ const skillNames = Array.isArray(data.skillNames) ? data.skillNames.filter((name) => typeof name === "string") : [];
55101
+ const showBubble = parts.text !== "" || parts.rest.length > 0;
55102
+ const compactImages = parts.attachments.filter((attachment) => attachment.type === "image").length > 1;
55103
+ const messageId = `user-${String(data.seq ?? props.node.id ?? "message")}`;
55104
+ const chatT = props.t;
55105
+ return (0, react.createElement)("div", {
55106
+ "data-chat-flow-kind": "user",
55107
+ style: {
55108
+ display: "flex",
55109
+ flexDirection: "column",
55110
+ alignItems: "flex-end",
55111
+ gap: 6
55112
+ }
55113
+ }, props.presentation.kind === "factory" ? props.presentation.userContent(props, {
55114
+ text: parts.text,
55115
+ attachments: parts.attachments.map((item) => item.type === "image" ? {
55116
+ type: "image",
55117
+ image: { attachment: item.attachment }
55118
+ } : item),
55119
+ extraBlocks: parts.rest,
55120
+ referenceLabels: labels
55121
+ }, {
55122
+ sessionLabels: labels,
55123
+ skillNames
55124
+ }) : (0, react.createElement)("div", { style: {
55125
+ display: "flex",
55126
+ flexDirection: "column",
55127
+ alignItems: "flex-end",
55128
+ gap: 8,
55129
+ minWidth: 0,
55130
+ maxWidth: "min(calc(var(--dsh-chat-content-width, 748px) * .702), 82%)"
55131
+ } }, parts.attachments.length > 0 ? (0, react.createElement)("div", {
55132
+ "data-message-attachments": true,
55133
+ style: {
55134
+ display: "flex",
55135
+ flexWrap: "wrap",
55136
+ justifyContent: "flex-end",
55137
+ gap: 8,
55138
+ maxWidth: "100%"
55139
+ }
55140
+ }, ...parts.attachments.map((attachment, index) => attachment.type === "image" ? (0, react.createElement)("div", { key: `image-${index}` }, props.presentation.images(props, {
55141
+ images: [{ attachment: attachment.attachment }],
55142
+ align: "end",
55143
+ compact: compactImages
55144
+ })) : createFileAttachment(attachment.file, index))) : null, showBubble ? (0, react.createElement)("div", { style: {
55145
+ boxSizing: "border-box",
55146
+ maxWidth: "100%",
55147
+ padding: "10px 16px",
55148
+ borderRadius: "var(--dsw-radius-xl, 18px)",
55149
+ color: require_theme.dshThemeColor.labelPrimary,
55150
+ background: "var(--dsw-specific-bubble, var(--dsw-alias-interactive-bg-hover, rgba(127,127,127,.08)))",
55151
+ fontSize: "var(--dsh-content-font-size, 14px)",
55152
+ lineHeight: "calc(22px + var(--dsh-content-font-delta, 0px))",
55153
+ whiteSpace: "pre-wrap",
55154
+ wordBreak: "break-word"
55155
+ } }, props.presentation.projectText(parts.text, labels, skillNames, "skill", typeof props.openFile === "function" && typeof props.openSkill === "function" ? {
55156
+ openFile: props.openFile,
55157
+ openSkill: props.openSkill
55158
+ } : void 0), ...parts.rest.map((block, index) => (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
55159
+ key: `extra-${index}`,
55160
+ label: chatT("message.extraBlock"),
55161
+ payload: block,
55162
+ truncatedLabel: (total) => chatT("json.truncated", { total })
55163
+ }))) : null, labels.length === 0 ? null : (0, react.createElement)("div", { style: {
55164
+ color: require_theme.dshThemeColor.labelTertiary,
55165
+ fontSize: "var(--dsh-content-font-size-secondary, 13px)",
55166
+ lineHeight: "calc(18px + var(--dsh-content-font-delta-secondary, 0px))"
55167
+ } }, chatT("message.referenceSummary", { labels: labels.join(chatT("message.referenceSeparator")) }))), (0, react.createElement)("div", { style: {
55168
+ display: "flex",
55169
+ alignItems: "center",
55170
+ alignSelf: "flex-end",
55171
+ height: "calc(28px + var(--dsh-content-font-delta, 0px))",
55172
+ gap: 8,
55173
+ color: require_theme.dshThemeColor.labelTertiary
55174
+ } }, typeof data.time === "number" ? (0, react.createElement)("span", { style: {
55175
+ paddingRight: 12,
55176
+ color: require_theme.dshThemeColor.labelTertiary,
55177
+ fontSize: "var(--dsh-content-font-size-secondary, 13px)",
55178
+ whiteSpace: "nowrap"
55179
+ } }, formatMessageTime(data.time)) : null, translationRecord === void 0 ? null : (0, react.createElement)(TranslationAction, {
55180
+ messageId,
55181
+ messageRole: "user",
55182
+ services: props.services,
55183
+ translationT: props.translationT,
55184
+ popupAlign: "end",
55185
+ record: translationRecord
55186
+ }), (0, react.createElement)(CopyAction, {
55187
+ text: parts.text,
55188
+ t: chatT
55189
+ })));
55190
+ }
55191
+ function createFileAttachment(file, index) {
55192
+ const name = typeof file.name === "string" ? file.name : "";
55193
+ const bytes = typeof file.bytes === "number" ? file.bytes : 0;
55194
+ return (0, react.createElement)("span", {
55195
+ key: `file-${index}`,
55196
+ title: name,
55197
+ style: {
55198
+ display: "inline-flex",
55199
+ alignItems: "center",
55200
+ minWidth: 0,
55201
+ maxWidth: "100%",
55202
+ gap: 8,
55203
+ padding: "8px 10px",
55204
+ border: `1px solid ${require_theme.dshThemeColor.border}`,
55205
+ borderRadius: 8,
55206
+ color: require_theme.dshThemeColor.labelPrimary,
55207
+ background: require_theme.dshThemeColor.surfaceSubtle
55208
+ }
55209
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
55210
+ path: name,
55211
+ style: { flex: "none" }
55212
+ }), (0, react.createElement)("span", { style: {
55213
+ display: "flex",
55214
+ flexDirection: "column",
55215
+ minWidth: 0,
55216
+ textAlign: "left"
55217
+ } }, (0, react.createElement)("span", { style: {
55218
+ overflow: "hidden",
55219
+ textOverflow: "ellipsis",
55220
+ whiteSpace: "nowrap"
55221
+ } }, name), (0, react.createElement)("span", { style: {
55222
+ color: require_theme.dshThemeColor.labelSecondary,
55223
+ fontSize: 11
55224
+ } }, [(0, _deepseek_ai_dsh_client_ui_primitives.fileExtension)(name).toUpperCase().slice(0, 8), (0, _deepseek_ai_dsh_client_ui_primitives.fileSizeText)(bytes)].filter(Boolean).join(" "))));
55225
+ }
55226
+ function CopyAction({ text, t: chatT }) {
55227
+ const [copied, setCopied] = (0, react.useState)(false);
55228
+ const timer = (0, react.useRef)(void 0);
55229
+ (0, react.useEffect)(() => () => {
55230
+ if (timer.current !== void 0) clearTimeout(timer.current);
55231
+ }, []);
55232
+ return (0, react.createElement)("button", {
55233
+ type: "button",
55234
+ title: copied ? chatT("copied") : chatT("copy"),
55235
+ "aria-label": copied ? chatT("copied") : chatT("copy"),
55236
+ onClick: () => {
55237
+ (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(text).then((success) => {
55238
+ if (!success) return;
55239
+ setCopied(true);
55240
+ if (timer.current !== void 0) clearTimeout(timer.current);
55241
+ timer.current = setTimeout(() => {
55242
+ timer.current = void 0;
55243
+ setCopied(false);
55244
+ }, 1e3);
55245
+ });
55246
+ },
55247
+ style: messageActionButtonStyle
55248
+ }, (0, react.createElement)(copied ? _deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular : _deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular));
55249
+ }
55250
+ function splitUserContent(content) {
55251
+ const text = [];
55252
+ const attachments = [];
55253
+ const rest = [];
55254
+ if (typeof content === "string") return {
55255
+ text: content,
55256
+ attachments,
55257
+ rest
55258
+ };
55259
+ if (!Array.isArray(content)) return {
55260
+ text: "",
55261
+ attachments,
55262
+ rest
55263
+ };
55264
+ for (const value of content) {
55265
+ const block = asRecord(value);
55266
+ if (block?.type === "text" && typeof block.text === "string") text.push(block.text);
55267
+ else if (block?.type === "image" && block.attachment !== void 0) attachments.push({
55268
+ type: "image",
55269
+ attachment: block.attachment
55270
+ });
55271
+ else if (block?.type === "file" && asRecord(block.attachment) !== void 0) attachments.push({
55272
+ type: "file",
55273
+ file: asRecord(block.attachment)
55274
+ });
55275
+ else rest.push(value);
55276
+ }
55277
+ return {
55278
+ text: text.join(""),
55279
+ attachments,
55280
+ rest
55281
+ };
55282
+ }
55283
+ function formatMessageTime(time) {
55284
+ const date = new Date(time);
55285
+ const now = /* @__PURE__ */ new Date();
55286
+ const options = date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate() ? {
55287
+ hour: "2-digit",
55288
+ minute: "2-digit"
55289
+ } : {
55290
+ ...date.getFullYear() === now.getFullYear() ? {} : { year: "numeric" },
55291
+ month: "2-digit",
55292
+ day: "2-digit",
55293
+ hour: "2-digit",
55294
+ minute: "2-digit"
55295
+ };
55296
+ return new Intl.DateTimeFormat(void 0, options).format(date);
55297
+ }
55298
+ /** DSH assistant-step renderer: keep each translation action adjacent to its source block. */
55299
+ function AssistantTranslationNodeView(props) {
55300
+ const data = props.node.data;
55301
+ const blocks = Array.isArray(data.blocks) ? data.blocks : [];
55302
+ const streaming = data.status === "running";
55303
+ const chatT = props.t;
55304
+ const markdownLabels = (0, react.useMemo)(() => createMarkdownLabels(chatT), [chatT]);
55305
+ const pathImages = (0, react.useMemo)(() => ({ resolve: resolveMarkdownImagePath }), []);
55306
+ const renderable = streaming || data.status === "interrupted" || blocks.some((block) => block.kind !== "tool-call");
55307
+ const eventSnapshot = renderable ? readEventSource(props.services, props.sessionId)?.getSnapshot() : void 0;
55308
+ const hasTranslation = renderable && blocks.some((block) => {
55309
+ if (block.kind !== "reasoning" && block.kind !== "text") return false;
55310
+ const outputKind = block.kind === "reasoning" ? "reasoning" : "assistant";
55311
+ const embedded = readRecord(block);
55312
+ if (embedded !== void 0 && (embedded.outputKind === void 0 || embedded.outputKind === outputKind)) return true;
55313
+ return eventSnapshot !== void 0 && findTranslationRecordForText(eventSnapshot, block.text, outputKind, data.turn, data.step) !== void 0;
55314
+ });
55315
+ const turn = props.node.location?.kind === "turn" || props.node.location?.kind === "step" ? props.node.location.turn : void 0;
55316
+ const tail = typeof props.useTurnData === "function" ? props.useTurnData("turn-tail") : void 0;
55317
+ const finalNode = data.finalNode;
55318
+ const fileOwner = turn?.status === "closed" && finalNode !== void 0 && tail?.closing?.finalNode?.seq === finalNode.seq ? {
55319
+ turn,
55320
+ seq: finalNode.seq,
55321
+ openFile: (path) => {
55322
+ props.openFile(path);
55323
+ }
55324
+ } : void 0;
55325
+ const mentions = fileOwner === void 0 || typeof props.fileMentions !== "function" ? void 0 : props.fileMentions(fileOwner);
55326
+ const turnProcess = props.turnProcess;
55327
+ const reasoningHidden = turnProcess !== void 0 && turnProcess.foldable === true && turnProcess.spec?.answerStep === data.step && turnProcess.spec?.inlineReasoning === true && turnProcess.open !== true;
55328
+ const rendered = [];
55329
+ const last = blocks.length - 1;
55330
+ const messageId = `turn-${data.turn}-step-${data.step}`;
55331
+ if (!renderable) return null;
55332
+ for (let index = 0; index < blocks.length; index += 1) {
55333
+ const block = blocks[index];
55334
+ if (block === void 0) continue;
55335
+ if (props.groupPart === "reasoning" && block.kind !== "reasoning") continue;
55336
+ if (props.groupPart === "response" && block.kind === "reasoning") continue;
55337
+ const running = streaming && index === last;
55338
+ if (block.kind === "text") {
55339
+ const translationRecord = readRecord(block) ?? (hasTranslation && eventSnapshot !== void 0 ? findTranslationRecordForText(eventSnapshot, block.text, "assistant", data.turn, data.step) : void 0);
55340
+ rendered.push((0, react.createElement)(AssistantTextContent, {
55341
+ key: `text-${index}`,
55342
+ messageId: `${messageId}-text-${index}`,
55343
+ sessionId: props.sessionId,
55344
+ services: props.services,
55345
+ translationT: props.translationT,
55346
+ text: block.text,
55347
+ streaming,
55348
+ markdownLabels,
55349
+ mentions,
55350
+ pathImages,
55351
+ translationRecord
55352
+ }));
55353
+ continue;
55354
+ }
55355
+ if (block.kind === "reasoning") {
55356
+ const translationRecord = readRecord(block) ?? (hasTranslation && eventSnapshot !== void 0 ? findTranslationRecordForText(eventSnapshot, block.text, "reasoning", data.turn, data.step) : void 0);
55357
+ rendered.push((0, react.createElement)(AssistantReasoningBlock, {
55358
+ key: `reasoning-${index}`,
55359
+ messageId: `${messageId}-reasoning-${index}`,
55360
+ sessionId: props.sessionId,
55361
+ services: props.services,
55362
+ translationT: props.translationT,
55363
+ chatT,
55364
+ text: block.text,
55365
+ ...translationRecord === void 0 ? {} : { translationRecord },
55366
+ running,
55367
+ hidden: reasoningHidden,
55368
+ reveal: () => turnProcess?.setOpen?.(true),
55369
+ useGroupAction: props.useGroupAction,
55370
+ renderFactorySlot: props.renderFactorySlot,
55371
+ markdownLabels,
55372
+ pathImages,
55373
+ mentions
55374
+ }));
55375
+ continue;
55376
+ }
55377
+ if (block.kind === "image") {
55378
+ const imageGroup = [block];
55379
+ while (index + 1 < blocks.length && blocks[index + 1]?.kind === "image") {
55380
+ const next = blocks[index + 1];
55381
+ if (next?.kind !== "image") break;
55382
+ imageGroup.push(next);
55383
+ index += 1;
55384
+ }
55385
+ rendered.push((0, react.createElement)("div", {
55386
+ key: `images-${index}`,
55387
+ style: { alignSelf: "flex-start" }
55388
+ }, props.presentation.images(props, {
55389
+ images: imageGroup.map((image) => ({ attachment: image.attachment })),
55390
+ align: "start"
55391
+ })));
55392
+ continue;
55393
+ }
55394
+ if (block.kind === "other") rendered.push((0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
55395
+ key: `other-${index}`,
55396
+ label: chatT("message.unknownBlock"),
55397
+ payload: block.block,
55398
+ truncatedLabel: (total) => chatT("json.truncated", { total })
55399
+ }));
55400
+ }
55401
+ return (0, react.createElement)("div", {
55402
+ "data-streaming": streaming || void 0,
55403
+ style: {
55404
+ display: "flex",
55405
+ flexDirection: "column",
55406
+ gap: 16,
55407
+ minWidth: 0,
55408
+ color: require_theme.dshThemeColor.labelPrimary,
55409
+ fontSize: "var(--dsh-content-font-size, 14px)",
55410
+ lineHeight: "calc(24px + var(--dsh-content-font-delta, 0px))"
55411
+ }
55412
+ }, ...rendered, data.status === "interrupted" ? (0, react.createElement)("span", { style: {
55413
+ alignSelf: "flex-start",
55414
+ padding: "0 6px",
55415
+ borderRadius: "var(--dsw-radius-sm, 4px)",
55416
+ color: require_theme.dshThemeColor.labelTertiary,
55417
+ background: require_theme.dshThemeColor.surfaceSubtle,
55418
+ fontSize: 11,
55419
+ lineHeight: "18px"
55420
+ } }, chatT("message.stopped")) : null);
55421
+ }
55422
+ function AssistantTextContent(props) {
55423
+ const { record } = useOutputTranslation({
55424
+ ...props,
55425
+ outputKind: "assistant",
55426
+ record: props.translationRecord
54864
55427
  });
54865
- add({
54866
- id: "sidebar-right-expand-020",
54867
- capability: "sidebar.right.expand",
54868
- supportedDsh,
54869
- runtime: "client",
54870
- priority: 30,
54871
- status: "supported",
54872
- introducedIn: "0.2.0-rc.1",
54873
- detect: (ctx) => hasMethods(read(ctx, "sidebarRight"), ["isExpanded", "toggleExpanded"]),
54874
- create: (ctx) => read(ctx, "sidebarRight")
55428
+ return (0, react.createElement)("div", {
55429
+ "data-codingns-translation-inline": true,
55430
+ style: { minWidth: 0 }
55431
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
55432
+ text: record?.translated ?? props.text,
55433
+ streaming: props.streaming,
55434
+ labels: props.markdownLabels,
55435
+ fileMentions: props.mentions,
55436
+ pathImages: props.pathImages
55437
+ }), record === void 0 ? null : (0, react.createElement)(TranslationAction, {
55438
+ messageId: props.messageId,
55439
+ sessionId: props.sessionId,
55440
+ messageRole: "assistant",
55441
+ outputKind: "assistant",
55442
+ services: props.services,
55443
+ translationT: props.translationT,
55444
+ record: props.translationRecord,
55445
+ inline: true
55446
+ }));
55447
+ }
55448
+ function AssistantReasoningBlock(props) {
55449
+ const [expanded, setExpanded] = (0, react.useState)(false);
55450
+ const groupRef = props.useGroupAction?.(props.hidden, props.reveal);
55451
+ const { record } = useOutputTranslation({
55452
+ ...props,
55453
+ outputKind: "reasoning",
55454
+ record: props.translationRecord
54875
55455
  });
55456
+ const summary = (record?.translated ?? props.text).split("\n").map((line) => line.replace(/[`*_#>]/gu, "").trim()).find(Boolean) ?? "";
55457
+ return (0, react.createElement)("div", {
55458
+ ref: groupRef,
55459
+ hidden: props.hidden,
55460
+ "data-turn-process-inline": props.hidden || void 0
55461
+ }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
55462
+ icon: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconThinkOutlineRegular, { size: 14 }),
55463
+ title: props.chatT("message.think"),
55464
+ open: expanded,
55465
+ expandable: true,
55466
+ expandOnRowClick: true,
55467
+ running: props.running,
55468
+ onToggle: () => setExpanded((value) => !value),
55469
+ collapsedContent: (0, react.createElement)("span", { style: {
55470
+ minWidth: 0,
55471
+ overflow: "hidden",
55472
+ color: require_theme.dshThemeColor.labelSecondary,
55473
+ fontSize: "var(--dsh-content-font-size-secondary, 13px)",
55474
+ textOverflow: "ellipsis",
55475
+ whiteSpace: "nowrap"
55476
+ } }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.TextShimmer, {
55477
+ active: props.running,
55478
+ children: summary
55479
+ }))
55480
+ }, expanded ? (0, react.createElement)(AssistantReasoningContent, {
55481
+ messageId: props.messageId,
55482
+ sessionId: props.sessionId,
55483
+ services: props.services,
55484
+ translationT: props.translationT,
55485
+ text: props.text,
55486
+ running: props.running,
55487
+ ...props.translationRecord === void 0 ? {} : { translationRecord: props.translationRecord },
55488
+ markdownLabels: props.markdownLabels,
55489
+ pathImages: props.pathImages,
55490
+ mentions: props.mentions,
55491
+ ...props.renderFactorySlot === void 0 ? {} : { renderFactorySlot: props.renderFactorySlot }
55492
+ }) : null));
54876
55493
  }
54877
55494
  /**
54878
- * 读取探测上下文里的服务或结构事实。
55495
+ * 思考块展开后的正文。
54879
55496
  *
54880
- * Cordis 的 Context 只在调用方 fiber 的 inject 链(或祖先 fiber 提供的服务)里
54881
- * 解析属性;直接读未注入的服务会抛 `cannot get property "x" without inject`,
54882
- * 把 `a || b` 形式的探测短路成失败。因此这里统一先走 `ctx.get(...)`(Cordis 提供
54883
- * 的免 inject 读取),再回退到普通属性读取,让探测只依据服务形状,不受消费方
54884
- * inject 列表影响。
55497
+ * DSH 原生 `ReasoningRow` 直接渲染 `MarkdownText`,运行时**没有**注册
55498
+ * `conversation.chat.reasoning.content` 工厂(`conversation.chat.*` 只有
55499
+ * `node` / `assistant-actions` / `commandview` / `turnTail`)。而 `renderFactorySlot`
55500
+ * 在工厂缺失时只渲染 `fallback`,缺省为 `null`——此前这里既不传 fallback,
55501
+ * 又把正文完全交给该工厂,于是展开思考后只剩翻译入口,译文一行都看不到。
55502
+ * 因此原生 MarkdownText 必须作为 fallback 传进去:没有工厂时按原生方式渲染,
55503
+ * 工厂存在时才允许表现层覆盖。
54885
55504
  */
54886
- function read(context, path) {
54887
- const [head, ...rest] = path.split(".");
54888
- if (head === void 0) return void 0;
54889
- let value = readKey(context, head);
54890
- for (const key of rest) value = readProperty(value, key);
54891
- return value;
55505
+ function AssistantReasoningContent(props) {
55506
+ const { record } = useOutputTranslation({
55507
+ ...props,
55508
+ outputKind: "reasoning",
55509
+ record: props.translationRecord
55510
+ });
55511
+ const displayText = record?.translated ?? props.text;
55512
+ const markdown = (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
55513
+ text: displayText,
55514
+ streaming: props.running,
55515
+ labels: props.markdownLabels,
55516
+ fileMentions: props.mentions,
55517
+ pathImages: props.pathImages,
55518
+ variant: "compact"
55519
+ });
55520
+ const content = props.renderFactorySlot === void 0 ? markdown : props.renderFactorySlot("conversation.chat.reasoning.content", {
55521
+ text: displayText,
55522
+ running: props.running
55523
+ }, { fallback: markdown });
55524
+ return (0, react.createElement)("div", {
55525
+ "data-codingns-translation-inline": true,
55526
+ style: { paddingTop: 8 }
55527
+ }, content, props.translationRecord === void 0 ? null : (0, react.createElement)(TranslationAction, {
55528
+ messageId: props.messageId,
55529
+ sessionId: props.sessionId,
55530
+ outputKind: "reasoning",
55531
+ messageRole: "assistant",
55532
+ services: props.services,
55533
+ translationT: props.translationT,
55534
+ record: props.translationRecord,
55535
+ inline: true
55536
+ }));
54892
55537
  }
54893
- /** 读取上下文上的服务(优先 `ctx.get`)或直接挂在上下文上的事实对象。 */
54894
- function readKey(context, key) {
54895
- if (typeof context !== "object" || context === null) return void 0;
54896
- const getter = readProperty(context, "get");
54897
- if (typeof getter === "function") try {
54898
- const value = getter.call(context, key);
54899
- if (value !== void 0) return value;
54900
- } catch {}
54901
- return readProperty(context, key);
55538
+ function createMarkdownLabels(chatT) {
55539
+ return {
55540
+ code: {
55541
+ copyLabel: chatT("copy"),
55542
+ copiedLabel: chatT("copied"),
55543
+ toolbarLabels: {
55544
+ codeLabel: chatT("codeBlock.title"),
55545
+ wrapLabel: chatT("codeBlock.wrap"),
55546
+ unwrapLabel: chatT("codeBlock.unwrap")
55547
+ }
55548
+ },
55549
+ footnotes: chatT("markdown.footnotes")
55550
+ };
54902
55551
  }
54903
- /** 读取对象属性;Cordis 代理对未注入的服务会抛错,统一按缺失处理。 */
54904
- function readProperty(target, key) {
54905
- if (typeof target !== "object" || target === null) return void 0;
55552
+ function resolveMarkdownImagePath(value) {
55553
+ if (typeof document === "undefined" || !value.startsWith("/") || /^[/\\]{2}/u.test(value) || /[\u0000-\u001f\u007f]/u.test(value)) return void 0;
55554
+ const base = document.baseURI;
55555
+ if (!/^https?:/u.test(base) && !base.startsWith("dsh-app://app/")) return void 0;
54906
55556
  try {
54907
- return Reflect.get(target, key);
55557
+ return new URL(`api/file?path=${encodeURIComponent(value)}`, base).href;
54908
55558
  } catch {
54909
55559
  return;
54910
55560
  }
54911
55561
  }
54912
- function hasMethods(value, methods) {
54913
- return typeof value === "object" && value !== null && methods.every((method) => typeof Reflect.get(value, method) === "function");
54914
- }
54915
- function hasAny(value, keys) {
54916
- return typeof value === "object" && value !== null && keys.some((key) => Reflect.get(value, key) !== void 0);
54917
- }
54918
- /** PeerHost Host 能力只接受显式注入的适配器,避免把普通 DSH 服务误报为已实现。 */
54919
- function addPeerHostHostRoutes(add) {
54920
- addPeerHostRoute(add, "peer-host.store", "peer-host-store", "peerHostStore");
54921
- addPeerHostRoute(add, "peer-host.handshake", "peer-host-handshake", "peerHostHandshake");
54922
- addPeerHostRoute(add, "peer-host.http-proxy", "peer-host-http-proxy", "peerHostHttpProxy");
54923
- addPeerHostRoute(add, "peer-host.ws-proxy", "peer-host-ws-proxy", "peerHostWsProxy");
54924
- addPeerHostRoute(add, "peer-host.aggregate", "peer-host-aggregate", "peerHostAggregate");
54925
- addPeerHostRoute(add, "peer-host.aggregated-transport", "peer-host-aggregated-transport", "peerHostAggregatedTransport");
54926
- addPeerHostRoute(add, "peer-host.target-capabilities", "peer-host-target-capabilities", "peerHostTargetCapabilities");
54927
- addPeerHostRoute(add, "peer-host.local-plugin-baseline", "peer-host-local-plugin-baseline", "peerHostLocalPluginBaseline");
54928
- addPeerHostRoute(add, "peer-host.relay-route", "peer-host-relay-route", "peerHostRelayRoute");
54929
- addPeerHostRoute(add, "peer-host.store", "peer-host-store-020", "peerHostStore", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54930
- addPeerHostRoute(add, "peer-host.handshake", "peer-host-handshake-020", "peerHostHandshake", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54931
- addPeerHostRoute(add, "peer-host.http-proxy", "peer-host-http-proxy-020", "peerHostHttpProxy", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54932
- addPeerHostRoute(add, "peer-host.ws-proxy", "peer-host-ws-proxy-020", "peerHostWsProxy", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54933
- addPeerHostRoute(add, "peer-host.aggregate", "peer-host-aggregate-020", "peerHostAggregate", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54934
- addPeerHostRoute(add, "peer-host.aggregated-transport", "peer-host-aggregated-transport-020", "peerHostAggregatedTransport", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54935
- addPeerHostRoute(add, "peer-host.target-capabilities", "peer-host-target-capabilities-020", "peerHostTargetCapabilities", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54936
- addPeerHostRoute(add, "peer-host.local-plugin-baseline", "peer-host-local-plugin-baseline-020", "peerHostLocalPluginBaseline", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54937
- addPeerHostRoute(add, "peer-host.relay-route", "peer-host-relay-route-020", "peerHostRelayRoute", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54938
- }
54939
55562
  /**
54940
- * PeerHost Client 导航能力由独立 adapter 注入;未注入时由 Feature 诊断降级。
54941
- *
54942
- * `peer-host.client-preboot-transport` 表示"页面在 DSH Connection 之前已可被聚合
54943
- * Transport 包装"。它不再等待官方 Provider 适配器,而是由插件自带的启动页 shim
54944
- * 提供:Web 与 Desktop 都注入同一个 shim,Desktop 用访问器接管运行时赋值。探测
54945
- * 只读 shim 状态,`external`(Transport 形状未知)时判为不可用,由 Feature 按
54946
- * "能力缺失只影响该模块"停用 PeerHost,而不是提示用户刷新。
55563
+ * 注册两个有实际翻译记录的消息渲染器;DSH 的用户气泡内容仍由统一主题令牌控制。
54947
55564
  */
54948
- function addPeerHostClientRoutes(add) {
54949
- addPeerHostRoute(add, "peer-host.native-navigation", "peer-host-native-navigation-legacy", "peerHostNativeNavigation", ">=0.1.5-rc.3 <=0.1.6", "deprecated");
54950
- addPeerHostRoute(add, "peer-host.native-navigation", "peer-host-native-navigation-modern", "peerHostNativeNavigation", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", 20);
54951
- addPeerHostRoute(add, "peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback", "peerHostRemoteWebContextFallback");
54952
- addPeerHostRoute(add, "peer-host.native-navigation", "peer-host-native-navigation-020", "peerHostNativeNavigation", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54953
- addPeerHostRoute(add, "peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback-020", "peerHostRemoteWebContextFallback", require_native_workspace_store.DSH_COMPATIBILITY, "supported", 30);
54954
- add({
54955
- id: "peer-host-client-preboot-transport-020",
54956
- capability: "peer-host.client-preboot-transport",
54957
- supportedDsh: require_native_workspace_store.DSH_COMPATIBILITY,
54958
- runtime: "client",
54959
- priority: 40,
54960
- status: "supported",
54961
- introducedIn: "0.2.0-rc.2",
54962
- detect: () => isPeerHostPrebootShimWrappable(),
54963
- create: () => readPeerHostPrebootShim()
55565
+ function registerSessionTranslationChatUi(services, facts = { primitives: _deepseek_ai_dsh_client_ui_primitives }) {
55566
+ const resolution = createDshCapabilityRegistry(services.dshVersion, "client", services, facts).getProfile(services).capabilities.get("conversation.message-presentation");
55567
+ const slots = services.slots;
55568
+ if (slots?.inject === void 0 || slots.register === void 0) return () => void 0;
55569
+ const removeStyles = installSessionTranslationChatStyles();
55570
+ const translationT = services.locale.bind("codingns");
55571
+ const removePendingActions = slots.inject("conversation.input.left", () => slots.register({
55572
+ name: "conversation.input.left",
55573
+ id: "codingns-translation-pending",
55574
+ inject: (sessionId) => ({
55575
+ services,
55576
+ sessionId,
55577
+ translationT
55578
+ })
55579
+ }, PendingTranslationActions));
55580
+ if (resolution?.status !== "ready") return () => {
55581
+ clearOutputTranslationRetries(services);
55582
+ removePendingActions();
55583
+ removeStyles();
55584
+ };
55585
+ const presentation = resolution.value;
55586
+ const removeRenderers = presentation.mount(() => {
55587
+ const removeUserRenderer = slots.inject("conversation.chat.node", () => slots.register({
55588
+ name: "conversation.chat.node",
55589
+ key: "user",
55590
+ priority: -100,
55591
+ locale: "chat",
55592
+ inject: (sessionId) => ({
55593
+ services,
55594
+ sessionId,
55595
+ translationT
55596
+ })
55597
+ }, (props) => UserMessageNodeView({
55598
+ ...props,
55599
+ presentation
55600
+ })));
55601
+ let removeAssistantRenderer;
55602
+ try {
55603
+ removeAssistantRenderer = slots.inject("conversation.chat.node", () => slots.register({
55604
+ name: "conversation.chat.node",
55605
+ key: "assistant-step",
55606
+ priority: -100,
55607
+ locale: "chat",
55608
+ inject: (sessionId) => ({
55609
+ services,
55610
+ sessionId,
55611
+ translationT
55612
+ })
55613
+ }, (props) => AssistantTranslationNodeView({
55614
+ ...props,
55615
+ presentation
55616
+ })));
55617
+ } catch (error) {
55618
+ removeUserRenderer();
55619
+ throw error;
55620
+ }
55621
+ return () => {
55622
+ removeAssistantRenderer();
55623
+ removeUserRenderer();
55624
+ };
54964
55625
  });
55626
+ return () => {
55627
+ clearOutputTranslationRetries(services);
55628
+ removePendingActions();
55629
+ removeRenderers();
55630
+ removeStyles();
55631
+ };
54965
55632
  }
54966
- /**
54967
- * shim 已安装且不是"结构不支持"时,页面 Transport 可被聚合层包装。
54968
- *
54969
- * 探测只读启动页已经写入的全局状态:`not-installed`(脚本未注入)与 `external`
54970
- * (Transport 形状未知)都判为不可用,让 Feature 按"能力缺失只影响该模块"停用
54971
- * PeerHost,而不是提示用户刷新。
54972
- */
54973
- function isPeerHostPrebootShimWrappable() {
54974
- const state = readPeerHostPrebootShimState();
54975
- return state !== "not-installed" && state !== "external";
55633
+ function installSessionTranslationChatStyles() {
55634
+ if (typeof document === "undefined") return () => void 0;
55635
+ const styleId = "codingns-session-translation-chat";
55636
+ if (document.head.querySelector(`style[data-plugin-css="${styleId}"]`) !== null) return () => void 0;
55637
+ const style = document.createElement("style");
55638
+ style.dataset.plugin = "codingns4dsh";
55639
+ style.dataset.pluginCss = styleId;
55640
+ style.textContent = `
55641
+ @keyframes codingns-translation-spin{to{transform:rotate(360deg)}}
55642
+ [data-codingns-translation-pending]{animation:codingns-translation-spin .8s linear infinite}
55643
+ @media(prefers-reduced-motion:reduce){[data-codingns-translation-pending]{animation-duration:1.6s}}
55644
+ [data-codingns-translation-inline] > div:not([data-codingns-translation-action]){display:contents}
55645
+ [data-codingns-translation-inline] > div:not([data-codingns-translation-action]) > p:last-child{display:inline;margin:0}
55646
+ `;
55647
+ document.head.appendChild(style);
55648
+ return () => style.remove();
54976
55649
  }
54977
- function readPeerHostPrebootShimState() {
54978
- const shim = readPeerHostPrebootShim();
54979
- if (shim === void 0) return "not-installed";
55650
+ function readEventSource(services, sessionId) {
55651
+ const sessions = services.sessions;
54980
55652
  try {
54981
- return typeof shim.getState === "function" ? String(shim.getState()) : "installed";
55653
+ return sessions?.binding?.(sessionId)?.eventSource;
54982
55654
  } catch {
54983
- return "not-installed";
55655
+ return;
54984
55656
  }
54985
55657
  }
54986
- function readPeerHostPrebootShim() {
54987
- try {
54988
- return globalThis[DSH_PEER_HOST_PREBOOT_SHIM_GLOBAL];
54989
- } catch {
55658
+ function findTranslationRecordForText(snapshot, text, outputKind, turn, step) {
55659
+ const entries = snapshot.entries ?? [];
55660
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
55661
+ const event = readEntryEvent(entries[index]);
55662
+ if (event === void 0 || !event.type.startsWith("assistant/")) continue;
55663
+ const eventData = asRecord(event.data);
55664
+ if (turn !== void 0 && typeof eventData?.turn === "number" && eventData.turn !== turn) continue;
55665
+ if (step !== void 0 && typeof eventData?.step === "number" && eventData.step !== step) continue;
55666
+ const candidates = [];
55667
+ collectRecordCandidates(event.data, candidates, /* @__PURE__ */ new Set());
55668
+ for (const candidate of candidates) {
55669
+ const record = readRecord(candidate);
55670
+ if (record === void 0 || record.original !== text && record.translated !== text) continue;
55671
+ if (outputKind !== void 0 && record.outputKind !== void 0 && record.outputKind !== outputKind) continue;
55672
+ return record;
55673
+ }
55674
+ }
55675
+ }
55676
+ function collectRecordCandidates(value, candidates, seen, depth = 0) {
55677
+ if (Array.isArray(value)) {
55678
+ for (const item of value) collectRecordCandidates(item, candidates, seen, depth + 1);
54990
55679
  return;
54991
55680
  }
55681
+ const record = asRecord(value);
55682
+ if (record === void 0 || seen.has(record) || depth > 7) return;
55683
+ seen.add(record);
55684
+ if (readRecord(record) !== void 0 || asRecord(record.codingnsTranslation) !== void 0) candidates.push(record);
55685
+ for (const key of [
55686
+ "codingnsTranslation",
55687
+ "source",
55688
+ "message",
55689
+ "content",
55690
+ "stream",
55691
+ "chunk",
55692
+ "block",
55693
+ "data"
55694
+ ]) if (record[key] !== void 0) collectRecordCandidates(record[key], candidates, seen, depth + 1);
54992
55695
  }
54993
- function addPeerHostRoute(add, capability, id, field, supportedDsh = ">=0.1.5-rc.3 <=0.1.7-rc.2", status = "supported", priority = 10) {
54994
- add({
54995
- id,
54996
- capability,
54997
- supportedDsh,
54998
- runtime: capability === "peer-host.native-navigation" || capability === "peer-host.remote-web-context-fallback" || capability === "peer-host.client-preboot-transport" ? "client" : "host",
54999
- priority,
55000
- status,
55001
- introducedIn: "0.1.5-rc.3",
55002
- detect: (context) => readPeerHostAdapter(context, field) !== void 0,
55003
- create: (context) => readPeerHostAdapter(context, field)
55004
- });
55696
+ function readEntryEvent(value) {
55697
+ const record = asRecord(value);
55698
+ return asRecord(record?.event) ?? (typeof record?.type === "string" ? record : void 0);
55005
55699
  }
55006
- function readPeerHostAdapter(context, field) {
55007
- if (Array.isArray(context)) return void 0;
55008
- return readKey(context, field);
55700
+ function readRecord(value) {
55701
+ const record = asRecord(value);
55702
+ const candidate = asRecord(record?.codingnsTranslation) ?? record;
55703
+ if (candidate?.original === void 0 || candidate.translated === void 0) return void 0;
55704
+ if (typeof candidate.original !== "string" || typeof candidate.translated !== "string") return void 0;
55705
+ const targetLanguage = readLanguage(candidate.targetLanguage);
55706
+ if (targetLanguage === void 0) return void 0;
55707
+ const model = readModel(candidate.model);
55708
+ const outputKind = candidate.outputKind === "assistant" || candidate.outputKind === "reasoning" ? candidate.outputKind : void 0;
55709
+ return {
55710
+ original: candidate.original,
55711
+ translated: candidate.translated,
55712
+ ...candidate.sourceLanguage === "zh" || candidate.sourceLanguage === "en" || candidate.sourceLanguage === "fr" || candidate.sourceLanguage === "de" || candidate.sourceLanguage === "ja" ? { sourceLanguage: candidate.sourceLanguage } : {},
55713
+ targetLanguage,
55714
+ bilingual: candidate.bilingual === true,
55715
+ ...outputKind === void 0 ? {} : { outputKind },
55716
+ ...candidate.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
55717
+ ...model === void 0 ? {} : { model },
55718
+ ...candidate.failed === true ? { failed: true } : {},
55719
+ ...require_session_translation.readSessionTranslationMetrics(candidate)
55720
+ };
55721
+ }
55722
+ function readModel(value) {
55723
+ const record = asRecord(value);
55724
+ if (typeof record?.provider !== "string" || typeof record.model !== "string" || record.provider.trim() === "" || record.model.trim() === "") return void 0;
55725
+ return {
55726
+ provider: record.provider,
55727
+ model: record.model
55728
+ };
55729
+ }
55730
+ function readInputRecord(value) {
55731
+ const candidate = asRecord(asRecord(asRecord(value)?.source)?.codingnsTranslationInput);
55732
+ if (candidate?.original === void 0 || candidate.translated === void 0) return void 0;
55733
+ if (typeof candidate.original !== "string" || typeof candidate.translated !== "string") return void 0;
55734
+ const targetLanguage = readLanguage(candidate.targetLanguage);
55735
+ if (targetLanguage === void 0) return void 0;
55736
+ const model = readModel(candidate.model);
55737
+ return {
55738
+ original: candidate.original,
55739
+ translated: candidate.translated,
55740
+ ...candidate.sourceLanguage === "zh" || candidate.sourceLanguage === "en" || candidate.sourceLanguage === "fr" || candidate.sourceLanguage === "de" || candidate.sourceLanguage === "ja" ? { sourceLanguage: candidate.sourceLanguage } : {},
55741
+ targetLanguage,
55742
+ ...candidate.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
55743
+ ...model === void 0 ? {} : { model },
55744
+ ...candidate.failed === true ? { failed: true } : {},
55745
+ ...require_session_translation.readSessionTranslationMetrics(candidate)
55746
+ };
55747
+ }
55748
+ function inputRecordForAction(record) {
55749
+ return {
55750
+ original: record.original,
55751
+ translated: record.translated,
55752
+ ...record.sourceLanguage === void 0 ? {} : { sourceLanguage: record.sourceLanguage },
55753
+ targetLanguage: record.targetLanguage,
55754
+ bilingual: false,
55755
+ ...record.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {},
55756
+ ...record.model === void 0 ? {} : { model: record.model },
55757
+ ...record.failed === true ? { failed: true } : {},
55758
+ ...require_session_translation.readSessionTranslationMetrics(record)
55759
+ };
55760
+ }
55761
+ function readLanguage(value) {
55762
+ return value === "zh" || value === "en" || value === "fr" || value === "de" || value === "ja" ? value : void 0;
55763
+ }
55764
+ function formatModel(model, t) {
55765
+ return model === void 0 ? t("translation.modelUnknown") : `${model.provider} / ${model.model}`;
55766
+ }
55767
+ function safeDomId(value) {
55768
+ return encodeURIComponent(value).replace(/%/gu, "-");
55769
+ }
55770
+ function asRecord(value) {
55771
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
55009
55772
  }
55010
55773
  //#endregion
55011
55774
  //#region src/dsh-capabilities/client/interaction-text-dom.ts
@@ -55417,6 +56180,10 @@ ${scope} [data-dockkit-strip-tabs] {
55417
56180
  capability: "conversation.interaction-translation",
55418
56181
  required: false,
55419
56182
  fallback: "degrade"
56183
+ }, {
56184
+ capability: "conversation.message-presentation",
56185
+ required: false,
56186
+ fallback: "degrade"
55420
56187
  }],
55421
56188
  ui: {
55422
56189
  label: "Session translation",
@@ -55538,6 +56305,15 @@ ${scope} [data-dockkit-strip-tabs] {
55538
56305
  translationModels: models,
55539
56306
  translationModel: void 0
55540
56307
  })
56308
+ }), (0, react.createElement)("div", { style: {
56309
+ ...require_theme.dshSettingsSectionHeaderStyle,
56310
+ marginTop: 12
56311
+ } }, (0, react.createElement)("span", { style: require_theme.dshSettingsFieldLabelStyle }, t("translation.rulesTitle"))), (0, react.createElement)(SessionTranslationRules, {
56312
+ rules: value.translationRules ?? [],
56313
+ disabled,
56314
+ pending: saving,
56315
+ t,
56316
+ onChange: (rules) => save({ translationRules: rules })
55541
56317
  }));
55542
56318
  }
55543
56319
  function Field({ label, children }) {
@@ -56125,7 +56901,7 @@ ${scope} [data-dockkit-strip-tabs] {
56125
56901
  marginLeft: "auto"
56126
56902
  },
56127
56903
  onClick: (event) => event.stopPropagation()
56128
- }, (0, react.createElement)(require_moss_voice_output.SettingsSwitch, {
56904
+ }, (0, react.createElement)(require_react_dom$1.SettingsSwitch, {
56129
56905
  variant: "module",
56130
56906
  "aria-label": label,
56131
56907
  checked,
@@ -56280,7 +57056,7 @@ ${scope} [data-dockkit-strip-tabs] {
56280
57056
  return value === void 0 ? void 0 : (({ cliSessions: _cliSessions, ...clientValue }) => clientValue)(value);
56281
57057
  }
56282
57058
  //#endregion
56283
- //#region node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.5/node_modules/@deepseek-ai/cosmokit/lib/index.js
57059
+ //#region node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.6-alpha.2/node_modules/@deepseek-ai/cosmokit/lib/index.js
56284
57060
  /** Return true when a value is `null` or `undefined`. */
56285
57061
  function isNullable(value) {
56286
57062
  return value === null || value === void 0;
@@ -56449,7 +57225,7 @@ ${scope} [data-dockkit-strip-tabs] {
56449
57225
  Time.template = template;
56450
57226
  })(Time || (Time = {}));
56451
57227
  //#endregion
56452
- //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4_@deepseek-ai+cordis-plugin-include@1.0.9_@deepseek-ai+cordis-plugin-loader@1.0.6-alpha.1/node_modules/@deepseek-ai/cordis/lib/index.js
57228
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.5-alpha.2_@deepseek-ai+cordis-plugin-include@1.0.10-alpha.2_@de_d750ba50d5bee7081316b89f08b32afa/node_modules/@deepseek-ai/cordis/lib/index.js
56453
57229
  /** Ordered collection of disposable values with O(1) deletion by value. */
56454
57230
  var DisposableList = class {
56455
57231
  sn = 0;
@@ -61821,12 +62597,21 @@ ${scope} [data-dockkit-strip-tabs] {
61821
62597
  function isInjectedStage0Runtime(scope = globalThis) {
61822
62598
  return scope[CODINGNS_STAGE0_GLOBAL] === true;
61823
62599
  }
61824
- route("session.title", "session-title-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["dsh-capabilities/host/session-title-adapter.ts", "host/features/session-title-optimization.ts"]), route("session.working-directory", "session-working-directory-021", "host", ">=0.2.1-alpha.2", "supported", ["host/terminal/terminal-controller.ts", "host/index.ts"]), route("llm.text", "llm-text-021", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", [
62600
+ route("session.prompt-assembly", "session-prompt-assembly-021", "host", ">=0.2.1-alpha.3 <=0.2.1-alpha.3", "supported", [
62601
+ "dsh-capabilities/host/session-prompt-adapter.ts",
62602
+ "host/features/session-prompt-translation.ts",
62603
+ "host/cli-adapters/feature.ts"
62604
+ ]), route("session.external-model-selection", "session-external-model-selection-021", "host", ">=0.2.1-alpha.3 <=0.2.1-alpha.3", "supported", ["dsh-capabilities/host/session-model-selection-adapter.ts", "host/cli-adapters/feature.ts"]), route("session.activation", "session-activation-020", "host", ">=0.2.0-rc.2 <=0.2.1-alpha.2", "supported", ["dsh-capabilities/host/session-activation-adapter.ts", "host/native-session-bridge.ts"]), route("session.activation", "session-activation-021", "host", ">=0.2.1-alpha.3 <=0.2.1-alpha.3", "supported", ["dsh-capabilities/host/session-activation-adapter.ts", "host/native-session-bridge.ts"]), route("conversation.message-presentation", "message-presentation-020", "client", ">=0.2.0-rc.2 <=0.2.1-alpha.2", "supported", ["dsh-capabilities/client/message-presentation-adapter.ts", "client/session-translation-chat.ts"]), route("conversation.message-presentation", "message-presentation-021", "client", ">=0.2.1-alpha.3 <=0.2.1-alpha.3", "supported", ["dsh-capabilities/client/message-presentation-adapter.ts", "client/session-translation-chat.ts"]), route("connection.peer", "connection.peer-021", "host", ">=0.2.1-alpha.3 <=0.2.1-alpha.3", "supported", [
62605
+ "dsh-capabilities/host/connection-peer-adapter.ts",
62606
+ "host/rpc.ts",
62607
+ "host/features/global-voice-rpc.ts",
62608
+ "host/modules/peer-host/peer-host-native-dispatch.ts"
62609
+ ]), route("connection.uplink", "connection.uplink-021", "host", ">=0.2.1-alpha.3 <=0.2.1-alpha.3", "supported", ["dsh-capabilities/host/native-dispatch-adapter.ts", "host/modules/peer-host/peer-host-native-dispatch.ts"]), route("session.title", "session-title-020", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", ["dsh-capabilities/host/session-title-adapter.ts", "host/features/session-title-optimization.ts"]), route("session.working-directory", "session-working-directory-021", "host", ">=0.2.1-alpha.2", "supported", ["host/terminal/terminal-controller.ts", "host/index.ts"]), route("llm.text", "llm-text-021", "host", require_native_workspace_store.DSH_COMPATIBILITY, "supported", [
61825
62610
  "dsh-capabilities/host/assistant-llm-adapter.ts",
61826
62611
  "host/features/assistant-text-chat.ts",
61827
62612
  "dsh-capabilities/host/session-title-adapter.ts",
61828
62613
  "host/features/session-title-optimization.ts"
61829
- ]), 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", require_native_workspace_store.DSH_COMPATIBILITY, "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", require_native_workspace_store.DSH_COMPATIBILITY, "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("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-alpha.2", "supported", ["client/terminal/ui.ts", "client/terminal/sharing.ts"]), route("conversation.interaction-translation", "interaction-presentation-021", "client", ">=0.2.1-alpha.1 <=0.2.1-alpha.2", "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"]), 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", [
62614
+ ]), 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("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-alpha.3", "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"]), 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", [
61830
62615
  "bootstrap/index.ts",
61831
62616
  "host/index-injection.ts",
61832
62617
  "client/features/peer-host.ts"
@@ -61850,7 +62635,7 @@ ${scope} [data-dockkit-strip-tabs] {
61850
62635
  };
61851
62636
  }
61852
62637
  //#endregion
61853
- //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.1-alpha.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
62638
+ //#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.1-alpha.3_@deepseek-ai+cordis@4.0.5-alpha.2/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
61854
62639
  /**
61855
62640
  * The `dsh-resource://file/…` address grammar: how a file is named across the
61856
62641
  * Sidebar and the resource model, built and parsed without touching a
@@ -67846,5 +68631,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
67846
68631
  });
67847
68632
 
67848
68633
  })();
67849
- // codingns-client-revision: f7ec32a7b3efd08f5abcbef533cb2176c06252bf20ad09640549492c82a5ebbe
68634
+ // codingns-client-revision: 2e9f1cf8b1415877388dec3f78d38b7ad5866162a49e617afa85f7edf56e6472
67850
68635
  //# sourceMappingURL=bundle.js.map