@jingyi0605/codingns4dsh 0.2.1-beta.10 → 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 (248) hide show
  1. package/README.en.md +7 -5
  2. package/README.md +12 -6
  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 +9713 -7350
  6. package/data/build/dist/client/bundle.js.map +1 -1
  7. package/data/build/dist/client/cli-slots.d.ts +13 -3
  8. package/data/build/dist/client/cli-slots.d.ts.map +1 -1
  9. package/data/build/dist/client/cli-slots.js +93 -18
  10. package/data/build/dist/client/cli-slots.js.map +1 -1
  11. package/data/build/dist/client/client.assistant-configuration-view.js +4 -3
  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 +415 -0
  14. package/data/build/dist/client/client.moss-voice-output.js.map +1 -0
  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.primitives-adapter.js.map +1 -1
  18. package/data/build/dist/client/client.react-dom.js +0 -404
  19. package/data/build/dist/client/client.react-dom.js.map +1 -1
  20. package/data/build/dist/client/client.session-translation.js +105 -2
  21. package/data/build/dist/client/client.session-translation.js.map +1 -1
  22. package/data/build/dist/client/client.transport.js +103 -11
  23. package/data/build/dist/client/client.transport.js.map +1 -1
  24. package/data/build/dist/client/conversation-translation-settings.d.ts +10 -0
  25. package/data/build/dist/client/conversation-translation-settings.d.ts.map +1 -0
  26. package/data/build/dist/client/conversation-translation-settings.js +52 -0
  27. package/data/build/dist/client/conversation-translation-settings.js.map +1 -0
  28. package/data/build/dist/client/desktop-assistant.js +569 -450
  29. package/data/build/dist/client/features/cli-adapters.d.ts.map +1 -1
  30. package/data/build/dist/client/features/cli-adapters.js +3 -1
  31. package/data/build/dist/client/features/cli-adapters.js.map +1 -1
  32. package/data/build/dist/client/features/session-translation.d.ts.map +1 -1
  33. package/data/build/dist/client/features/session-translation.js +49 -48
  34. package/data/build/dist/client/features/session-translation.js.map +1 -1
  35. package/data/build/dist/client/locales/panels.d.ts.map +1 -1
  36. package/data/build/dist/client/locales/panels.js +103 -11
  37. package/data/build/dist/client/locales/panels.js.map +1 -1
  38. package/data/build/dist/client/native-model-translation-menu.d.ts +6 -0
  39. package/data/build/dist/client/native-model-translation-menu.d.ts.map +1 -0
  40. package/data/build/dist/client/native-model-translation-menu.js +57 -0
  41. package/data/build/dist/client/native-model-translation-menu.js.map +1 -0
  42. package/data/build/dist/client/native-translation-default.d.ts +6 -0
  43. package/data/build/dist/client/native-translation-default.d.ts.map +1 -0
  44. package/data/build/dist/client/native-translation-default.js +30 -0
  45. package/data/build/dist/client/native-translation-default.js.map +1 -0
  46. package/data/build/dist/client/session-translation-chat.d.ts +23 -2
  47. package/data/build/dist/client/session-translation-chat.d.ts.map +1 -1
  48. package/data/build/dist/client/session-translation-chat.js +238 -72
  49. package/data/build/dist/client/session-translation-chat.js.map +1 -1
  50. package/data/build/dist/client/session-translation-interactions.d.ts +31 -0
  51. package/data/build/dist/client/session-translation-interactions.d.ts.map +1 -0
  52. package/data/build/dist/client/session-translation-interactions.js +158 -0
  53. package/data/build/dist/client/session-translation-interactions.js.map +1 -0
  54. package/data/build/dist/client/session-translation-model-pool.d.ts +16 -0
  55. package/data/build/dist/client/session-translation-model-pool.d.ts.map +1 -0
  56. package/data/build/dist/client/session-translation-model-pool.js +246 -0
  57. package/data/build/dist/client/session-translation-model-pool.js.map +1 -0
  58. package/data/build/dist/client/session-translation-pending-dom.d.ts +8 -0
  59. package/data/build/dist/client/session-translation-pending-dom.d.ts.map +1 -0
  60. package/data/build/dist/client/session-translation-pending-dom.js +58 -0
  61. package/data/build/dist/client/session-translation-pending-dom.js.map +1 -0
  62. package/data/build/dist/client/session-translation-retry.d.ts +16 -0
  63. package/data/build/dist/client/session-translation-retry.d.ts.map +1 -0
  64. package/data/build/dist/client/session-translation-retry.js +66 -0
  65. package/data/build/dist/client/session-translation-retry.js.map +1 -0
  66. package/data/build/dist/client/session-translation-rules.d.ts +13 -0
  67. package/data/build/dist/client/session-translation-rules.d.ts.map +1 -0
  68. package/data/build/dist/client/session-translation-rules.js +58 -0
  69. package/data/build/dist/client/session-translation-rules.js.map +1 -0
  70. package/data/build/dist/client/style.css +276 -276
  71. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.d.ts +30 -0
  72. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.d.ts.map +1 -0
  73. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.js +93 -0
  74. package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.js.map +1 -0
  75. package/data/build/dist/dsh-capabilities/client/interaction-text-dom.d.ts +12 -0
  76. package/data/build/dist/dsh-capabilities/client/interaction-text-dom.d.ts.map +1 -0
  77. package/data/build/dist/dsh-capabilities/client/interaction-text-dom.js +181 -0
  78. package/data/build/dist/dsh-capabilities/client/interaction-text-dom.js.map +1 -0
  79. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.d.ts +19 -0
  80. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.d.ts.map +1 -0
  81. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.js +39 -0
  82. package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.js.map +1 -0
  83. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +1 -0
  84. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts.map +1 -1
  85. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +1 -0
  86. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js.map +1 -1
  87. package/data/build/dist/dsh-capabilities/client/question-history-adapter.d.ts +20 -0
  88. package/data/build/dist/dsh-capabilities/client/question-history-adapter.d.ts.map +1 -0
  89. package/data/build/dist/dsh-capabilities/client/question-history-adapter.js +65 -0
  90. package/data/build/dist/dsh-capabilities/client/question-history-adapter.js.map +1 -0
  91. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.d.ts +32 -0
  92. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.d.ts.map +1 -0
  93. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.js +90 -0
  94. package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.js.map +1 -0
  95. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.d.ts +10 -0
  96. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.d.ts.map +1 -0
  97. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.js +34 -0
  98. package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.js.map +1 -0
  99. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.d.ts +21 -0
  100. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.d.ts.map +1 -0
  101. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.js +11 -0
  102. package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.js.map +1 -0
  103. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.d.ts +17 -0
  104. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.d.ts.map +1 -0
  105. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.js +37 -0
  106. package/data/build/dist/dsh-capabilities/host/session-activation-adapter.js.map +1 -0
  107. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts +17 -0
  108. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts.map +1 -0
  109. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js +45 -0
  110. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js.map +1 -0
  111. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.d.ts +28 -0
  112. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.d.ts.map +1 -0
  113. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.js +31 -0
  114. package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.js.map +1 -0
  115. package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
  116. package/data/build/dist/dsh-capabilities/matrix.js +12 -3
  117. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  118. package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
  119. package/data/build/dist/dsh-capabilities/routes.js +26 -3
  120. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  121. package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
  122. package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
  123. package/data/build/dist/dsh-capabilities/types.js.map +1 -1
  124. package/data/build/dist/host/cli-adapters/antigravity-driver.js +1 -1
  125. package/data/build/dist/host/cli-adapters/antigravity-driver.js.map +1 -1
  126. package/data/build/dist/host/cli-adapters/attachment-utils.d.ts +4 -3
  127. package/data/build/dist/host/cli-adapters/attachment-utils.d.ts.map +1 -1
  128. package/data/build/dist/host/cli-adapters/attachment-utils.js +9 -8
  129. package/data/build/dist/host/cli-adapters/attachment-utils.js.map +1 -1
  130. package/data/build/dist/host/cli-adapters/claude-driver.js +1 -1
  131. package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
  132. package/data/build/dist/host/cli-adapters/command-code-driver.js +1 -1
  133. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  134. package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
  135. package/data/build/dist/host/cli-adapters/driver.d.ts.map +1 -1
  136. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +2 -0
  137. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  138. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +28 -11
  139. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  140. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  141. package/data/build/dist/host/cli-adapters/feature.js +369 -70
  142. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  143. package/data/build/dist/host/cli-adapters/gemini-driver.js +1 -1
  144. package/data/build/dist/host/cli-adapters/gemini-driver.js.map +1 -1
  145. package/data/build/dist/host/cli-adapters/grok-driver.d.ts +1 -0
  146. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  147. package/data/build/dist/host/cli-adapters/grok-driver.js +128 -40
  148. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  149. package/data/build/dist/host/cli-adapters/kimi-driver.js +2 -2
  150. package/data/build/dist/host/cli-adapters/kimi-driver.js.map +1 -1
  151. package/data/build/dist/host/cli-adapters/mcode-driver.js +1 -1
  152. package/data/build/dist/host/cli-adapters/mcode-driver.js.map +1 -1
  153. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js +2 -2
  154. package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js.map +1 -1
  155. package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts.map +1 -1
  156. package/data/build/dist/host/cli-adapters/native-team-subagent.js +2 -1
  157. package/data/build/dist/host/cli-adapters/native-team-subagent.js.map +1 -1
  158. package/data/build/dist/host/cli-adapters/pi-driver.js +1 -1
  159. package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
  160. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  161. package/data/build/dist/host/cli-adapters/registry.js +25 -16
  162. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  163. package/data/build/dist/host/cli-adapters/zcode-driver.js +1 -1
  164. package/data/build/dist/host/cli-adapters/zcode-driver.js.map +1 -1
  165. package/data/build/dist/host/features/global-voice-rpc.d.ts.map +1 -1
  166. package/data/build/dist/host/features/global-voice-rpc.js +2 -3
  167. package/data/build/dist/host/features/global-voice-rpc.js.map +1 -1
  168. package/data/build/dist/host/features/interaction-translation.d.ts +9 -0
  169. package/data/build/dist/host/features/interaction-translation.d.ts.map +1 -0
  170. package/data/build/dist/host/features/interaction-translation.js +168 -0
  171. package/data/build/dist/host/features/interaction-translation.js.map +1 -0
  172. package/data/build/dist/host/features/peer-host.js +6 -6
  173. package/data/build/dist/host/features/peer-host.js.map +1 -1
  174. package/data/build/dist/host/features/session-prompt-translation.d.ts +10 -0
  175. package/data/build/dist/host/features/session-prompt-translation.d.ts.map +1 -0
  176. package/data/build/dist/host/features/session-prompt-translation.js +197 -0
  177. package/data/build/dist/host/features/session-prompt-translation.js.map +1 -0
  178. package/data/build/dist/host/features/session-translation-protection.d.ts +16 -0
  179. package/data/build/dist/host/features/session-translation-protection.d.ts.map +1 -0
  180. package/data/build/dist/host/features/session-translation-protection.js +183 -0
  181. package/data/build/dist/host/features/session-translation-protection.js.map +1 -0
  182. package/data/build/dist/host/features/session-translation-recovery.d.ts +20 -0
  183. package/data/build/dist/host/features/session-translation-recovery.d.ts.map +1 -0
  184. package/data/build/dist/host/features/session-translation-recovery.js +122 -0
  185. package/data/build/dist/host/features/session-translation-recovery.js.map +1 -0
  186. package/data/build/dist/host/features/session-translation-runtime.d.ts +16 -0
  187. package/data/build/dist/host/features/session-translation-runtime.d.ts.map +1 -0
  188. package/data/build/dist/host/features/session-translation-runtime.js +85 -0
  189. package/data/build/dist/host/features/session-translation-runtime.js.map +1 -0
  190. package/data/build/dist/host/features/session-translation-service.d.ts +14 -4
  191. package/data/build/dist/host/features/session-translation-service.d.ts.map +1 -1
  192. package/data/build/dist/host/features/session-translation-service.js +217 -211
  193. package/data/build/dist/host/features/session-translation-service.js.map +1 -1
  194. package/data/build/dist/host/features/session-translation.d.ts.map +1 -1
  195. package/data/build/dist/host/features/session-translation.js +5 -2
  196. package/data/build/dist/host/features/session-translation.js.map +1 -1
  197. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts +2 -2
  198. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts.map +1 -1
  199. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js +10 -9
  200. package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js.map +1 -1
  201. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.d.ts +3 -3
  202. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.d.ts.map +1 -1
  203. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.js +26 -14
  204. package/data/build/dist/host/modules/peer-host/peer-host-native-streams.js.map +1 -1
  205. package/data/build/dist/host/native-session-bridge.d.ts +2 -1
  206. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  207. package/data/build/dist/host/native-session-bridge.js +7 -15
  208. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  209. package/data/build/dist/host/rpc.d.ts.map +1 -1
  210. package/data/build/dist/host/rpc.js +14 -8
  211. package/data/build/dist/host/rpc.js.map +1 -1
  212. package/data/build/dist/host/settings.d.ts.map +1 -1
  213. package/data/build/dist/host/settings.js +10 -2
  214. package/data/build/dist/host/settings.js.map +1 -1
  215. package/data/build/dist/shared/attachment-prompts.d.ts +11 -0
  216. package/data/build/dist/shared/attachment-prompts.d.ts.map +1 -0
  217. package/data/build/dist/shared/attachment-prompts.js +17 -0
  218. package/data/build/dist/shared/attachment-prompts.js.map +1 -0
  219. package/data/build/dist/shared/contracts/cli-adapter.d.ts +8 -1
  220. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  221. package/data/build/dist/shared/contracts/errors.d.ts +2 -2
  222. package/data/build/dist/shared/contracts/interaction-presentation.d.ts +32 -0
  223. package/data/build/dist/shared/contracts/interaction-presentation.d.ts.map +1 -0
  224. package/data/build/dist/shared/contracts/interaction-presentation.js +2 -0
  225. package/data/build/dist/shared/contracts/interaction-presentation.js.map +1 -0
  226. package/data/build/dist/shared/contracts/interaction-translation.d.ts +53 -0
  227. package/data/build/dist/shared/contracts/interaction-translation.d.ts.map +1 -0
  228. package/data/build/dist/shared/contracts/interaction-translation.js +44 -0
  229. package/data/build/dist/shared/contracts/interaction-translation.js.map +1 -0
  230. package/data/build/dist/shared/contracts/session-translation.d.ts +75 -7
  231. package/data/build/dist/shared/contracts/session-translation.d.ts.map +1 -1
  232. package/data/build/dist/shared/contracts/session-translation.js +132 -2
  233. package/data/build/dist/shared/contracts/session-translation.js.map +1 -1
  234. package/data/build/dist/shared/contracts/version.d.ts +4 -4
  235. package/data/build/dist/shared/contracts/version.js +3 -3
  236. package/data/build/dist/shared/index.d.ts +1 -1
  237. package/data/build/dist/shared/index.d.ts.map +1 -1
  238. package/data/build/dist/shared/index.js +1 -1
  239. package/data/build/dist/shared/index.js.map +1 -1
  240. package/data/build/dist/shared/translation-indicator.d.ts +26 -0
  241. package/data/build/dist/shared/translation-indicator.d.ts.map +1 -0
  242. package/data/build/dist/shared/translation-indicator.js +29 -0
  243. package/data/build/dist/shared/translation-indicator.js.map +1 -0
  244. package/package.json +35 -34
  245. package/profile/README.md +2 -2
  246. package/profile/package.json +3 -3
  247. package/profile/version.json +3 -3
  248. package/version.json +3 -3
@@ -0,0 +1,415 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@jingyi0605/codingns4dsh",
3
+ chunk: "client.moss-voice-output.js",
4
+ factory: (require) => {
5
+ var module = { exports: {} };
6
+ var exports = module.exports;
7
+ const require_manager = require("@jingyi0605/codingns4dsh/client.manager.js");
8
+ const require_primitives_adapter = require("@jingyi0605/codingns4dsh/client.primitives-adapter.js");
9
+ //#region src/client/peer-host-color.ts
10
+ /**
11
+ * 工作区标签配色的推导与缓存。
12
+ *
13
+ * 用户在 PeerHost 管理里显式配置的颜色优先;没有配置时按 Host 名称推导一个稳定
14
+ * 颜色,保证同一台机器在多次刷新、多个工作区之间颜色一致——颜色本身是识别手段,
15
+ * 随机色会让标签失去意义。
16
+ */
17
+ /** 无显式配色时使用的候选色板;与 PEER_HOST_COLOR_PRESETS 保持同一组观感。 */
18
+ const FALLBACK_PALETTE = [
19
+ "#1677ff",
20
+ "#722ed1",
21
+ "#13c2c2",
22
+ "#52c41a",
23
+ "#fa8c16",
24
+ "#eb2f96",
25
+ "#f5222d",
26
+ "#8c8c8c"
27
+ ];
28
+ const derivedCache = /* @__PURE__ */ new Map();
29
+ /**
30
+ * 解析某台 Host 的工作区标签颜色。
31
+ *
32
+ * @param explicit - 用户在 PeerHost 配置里保存的颜色;非法或缺省时走推导。
33
+ * @param seed - 推导种子,通常用 PeerHost 名称;同一名称始终得到同一颜色。
34
+ * @returns `#rrggbb` 形式的小写颜色。
35
+ */
36
+ function resolvePeerHostColor(explicit, seed) {
37
+ const configured = require_primitives_adapter.normalizePeerHostColor(explicit);
38
+ if (configured !== null) return configured;
39
+ const key = seed.trim() === "" ? "peer-host" : seed.trim();
40
+ const cached = derivedCache.get(key);
41
+ if (cached !== void 0) return cached;
42
+ const color = FALLBACK_PALETTE[hashString(key) % FALLBACK_PALETTE.length];
43
+ derivedCache.set(key, color);
44
+ return color;
45
+ }
46
+ /** FNV-1a 32 位哈希;只用于选色,不需要密码学强度。 */
47
+ function hashString(value) {
48
+ let hash = 2166136261;
49
+ for (let index = 0; index < value.length; index += 1) {
50
+ hash ^= value.charCodeAt(index);
51
+ hash = Math.imul(hash, 16777619) >>> 0;
52
+ }
53
+ return hash >>> 0;
54
+ }
55
+ /** 标签胶囊的底色:与归档面板 Agent 徽标保持同一种 `color-mix` 写法。 */
56
+ function peerHostTagBackground(color) {
57
+ return `color-mix(in srgb, ${color} 16%, transparent)`;
58
+ }
59
+ /** 标签文字色;直接使用配置色,保证明暗主题下都有足够对比。 */
60
+ function peerHostTagForeground(color) {
61
+ return color;
62
+ }
63
+ /** 工作区列表与关联项目表共用的 Host 胶囊标签基础样式。 */
64
+ function peerHostTagStyle(color) {
65
+ return {
66
+ boxSizing: "border-box",
67
+ overflow: "hidden",
68
+ textOverflow: "ellipsis",
69
+ whiteSpace: "nowrap",
70
+ padding: "1px 6px",
71
+ borderRadius: "999px",
72
+ fontSize: "10px",
73
+ lineHeight: "1.5",
74
+ pointerEvents: "none",
75
+ color: peerHostTagForeground(color),
76
+ background: peerHostTagBackground(color)
77
+ };
78
+ }
79
+ //#endregion
80
+ //#region src/shared/voice-diagnostics.ts
81
+ const allowedFields = new Set(`ownerId clientId callId requestId diagnosticId epoch sequence firstSequence lastSequence
82
+ action state phase backend provider model code errorName status durationMs waitMs firstAudioMs firstTextMs
83
+ firstSentenceMs firstPlaybackMs queueMs gapMs intervalMs maxIntervalMs processMs maxProcessMs decodeMs
84
+ maxDecodeMs audioMs bytes pendingBytes pending frames chunks samples sampleRate inputRate threads tokens
85
+ textLength systemLength messageCount toolCount count dropped stale aborted completed continuation muted
86
+ sourceCount contextState processor cpuPercent rssMb heapMb eventLoopMeanMs eventLoopMaxMs eventLoopP99Ms
87
+ realTimeFactor generationMs codecMs transportMs segment generationFrames fileIndex
88
+ pcmBytes headerBytes pendingAudioMs inFlightMs endpointSilenceMs cached streaming
89
+ webSearchAvailable searchRegistration`.split(/\s+/u));
90
+ function sanitizeVoiceDiagnosticFields(value) {
91
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
92
+ const fields = {};
93
+ for (const key of allowedFields) {
94
+ const item = value[key];
95
+ if (typeof item === "number" && Number.isFinite(item) || typeof item === "boolean" || item === null) fields[key] = item;
96
+ else if (typeof item === "string") fields[key] = item.slice(0, 160);
97
+ }
98
+ return fields;
99
+ }
100
+ function voiceDiagnosticId() {
101
+ return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
102
+ }
103
+ function voiceDiagnosticError(error) {
104
+ return error instanceof Error ? error.name : "UnknownError";
105
+ }
106
+ //#endregion
107
+ //#region src/client/moss-voice-output.ts
108
+ /** 可取消的 PCM 播放器;同一轮的各段串行生成,生成与播放并行。 */
109
+ var MossVoiceOutput = class {
110
+ options;
111
+ context;
112
+ abort;
113
+ sources = /* @__PURE__ */ new Set();
114
+ sequence = 0;
115
+ outputDeviceId = "";
116
+ nextStart = 0;
117
+ gain;
118
+ muted = false;
119
+ volume = 1;
120
+ constructor(options = {}) {
121
+ this.options = options;
122
+ }
123
+ get outputDeviceSupported() {
124
+ return typeof (globalThis.AudioContext?.prototype)?.setSinkId === "function";
125
+ }
126
+ /** 在点击开始或试听时调用,保留浏览器要求的用户手势。 */
127
+ async prepare() {
128
+ if (this.context === void 0 || this.context.state === "closed") this.context = this.options.context?.() ?? new AudioContext();
129
+ if (this.gain === void 0) {
130
+ this.gain = this.context.createGain();
131
+ this.gain.gain.value = this.muted ? 0 : this.volume;
132
+ this.gain.connect(this.context.destination);
133
+ }
134
+ if (this.context.state === "suspended") await this.context.resume();
135
+ if (this.outputDeviceId !== "" && typeof this.context.setSinkId === "function") await this.context.setSinkId(this.outputDeviceId);
136
+ }
137
+ async setOutputDevice(id) {
138
+ if (!this.outputDeviceSupported) throw new Error("当前浏览器不支持 MOSS 播放设备选择");
139
+ if (this.context !== void 0) await this.context.setSinkId(id);
140
+ this.outputDeviceId = id;
141
+ }
142
+ /** 输出静音不中断推理或时间线,恢复后继续听当前播报。 */
143
+ setMuted(muted) {
144
+ this.muted = muted;
145
+ if (this.gain !== void 0) this.gain.gain.value = muted ? 0 : this.volume;
146
+ }
147
+ async speak(text, voiceId, onStart, parameters) {
148
+ this.cancel();
149
+ const sequence = this.sequence;
150
+ if (!await this.append(text, voiceId, onStart, parameters) || sequence !== this.sequence) return false;
151
+ return this.finish();
152
+ }
153
+ /** 由文本队列串行调用;收到生成结束即可提交下一段,不取消仍在播放的前一段。 */
154
+ async append(text, voiceId, onStart, parameters) {
155
+ const started = performance.now();
156
+ const diagnosticId = voiceDiagnosticId();
157
+ const fields = {
158
+ ...this.options.traceContext?.(),
159
+ diagnosticId,
160
+ textLength: text.length
161
+ };
162
+ const trace = (event, metrics) => this.options.trace?.(`client.tts.${event}`, {
163
+ ...fields,
164
+ ...metrics
165
+ });
166
+ let chunks = 0;
167
+ let audioMs = 0;
168
+ let lastChunkAt = started;
169
+ const playback = require_manager.readAssistantTtsParameters(parameters);
170
+ const sequence = this.sequence;
171
+ const continuation = this.abort !== void 0;
172
+ const abort = this.abort ?? new AbortController();
173
+ this.abort = abort;
174
+ const readerSignal = abort.signal;
175
+ trace("start", { continuation });
176
+ try {
177
+ await this.prepare();
178
+ if (readerSignal.aborted) return false;
179
+ const queueStarted = performance.now();
180
+ await this.waitUntil(() => this.sources.size === 0 || this.nextStart - this.context.currentTime <= 5, readerSignal);
181
+ if (readerSignal.aborted) return false;
182
+ trace("queue_ready", {
183
+ waitMs: performance.now() - queueStarted,
184
+ queueMs: Math.max(0, this.nextStart - this.context.currentTime) * 1e3
185
+ });
186
+ this.volume = playback.volume;
187
+ this.gain.gain.value = this.muted ? 0 : this.volume;
188
+ const response = await (this.options.fetch ?? globalThis.fetch)(new URL(require_manager.ASSISTANT_TTS_PATH, globalThis.location?.origin ?? "http://localhost"), {
189
+ method: "POST",
190
+ credentials: "same-origin",
191
+ signal: readerSignal,
192
+ headers: {
193
+ "content-type": "application/json",
194
+ accept: "application/x-ndjson"
195
+ },
196
+ body: JSON.stringify({
197
+ text,
198
+ parameters: playback,
199
+ diagnosticId,
200
+ ...voiceId === void 0 ? {} : { voiceId },
201
+ ...fields.requestId === void 0 ? {} : { requestId: fields.requestId },
202
+ ...fields.ownerId === void 0 ? {} : { ownerId: fields.ownerId }
203
+ })
204
+ });
205
+ trace("headers", {
206
+ status: response.status,
207
+ durationMs: performance.now() - started
208
+ });
209
+ if (!response.ok) {
210
+ const value = await response.json().catch(() => ({}));
211
+ throw new Error(typeof value.error === "string" ? value.error : `Host TTS 请求失败(${response.status})`);
212
+ }
213
+ if (response.body === null) throw new Error("Host TTS 响应缺少音频流");
214
+ const reader = response.body.getReader();
215
+ const decoder = new TextDecoder();
216
+ let buffer = "";
217
+ let completed = false;
218
+ let played = false;
219
+ try {
220
+ while (true) {
221
+ const next = await reader.read();
222
+ if (readerSignal.aborted) return false;
223
+ if (next.done) break;
224
+ buffer += decoder.decode(next.value, { stream: true });
225
+ if (buffer.length > 2097152) throw new Error("Host TTS 音频事件过大");
226
+ let boundary = buffer.indexOf("\n");
227
+ while (boundary >= 0) {
228
+ const line = buffer.slice(0, boundary).trim();
229
+ buffer = buffer.slice(boundary + 1);
230
+ if (line !== "") {
231
+ const event = JSON.parse(line);
232
+ if (completed) throw new Error("Host TTS 在完成后继续返回音频");
233
+ if (event.type === "error") throw new Error(String(event.message));
234
+ if (event.type === "done") completed = true;
235
+ else if (event.type === "audio") {
236
+ const arrived = performance.now();
237
+ if (chunks === 0) trace("first_audio", { firstAudioMs: arrived - started });
238
+ const samples = decodeMossPcm(event);
239
+ const decodeMs = performance.now() - arrived;
240
+ chunks++;
241
+ audioMs += samples.length / Number(event.sampleRate) * 1e3;
242
+ trace("chunk", {
243
+ chunks,
244
+ decodeMs,
245
+ samples: samples.length,
246
+ audioMs: samples.length / Number(event.sampleRate) * 1e3,
247
+ intervalMs: arrived - lastChunkAt,
248
+ queueMs: Math.max(0, this.nextStart - this.context.currentTime) * 1e3
249
+ });
250
+ lastChunkAt = arrived;
251
+ if (!played && continuation) this.nextStart += playback.segmentPauseMs / 1e3;
252
+ await this.waitUntil(() => this.sources.size === 0 || this.nextStart - this.context.currentTime <= 5, readerSignal);
253
+ if (readerSignal.aborted) return false;
254
+ this.enqueue(samples, Number(event.sampleRate), playback.rate, trace, chunks === 1 && !continuation);
255
+ if (!played) {
256
+ played = true;
257
+ onStart?.();
258
+ }
259
+ } else throw new Error("Host TTS 返回未知事件");
260
+ }
261
+ boundary = buffer.indexOf("\n");
262
+ }
263
+ }
264
+ } finally {
265
+ await reader.cancel().catch(() => void 0);
266
+ reader.releaseLock();
267
+ }
268
+ if (!completed || !played || buffer.trim() !== "") throw new Error("Host TTS 音频流未完整结束");
269
+ trace("generated", {
270
+ durationMs: performance.now() - started,
271
+ chunks,
272
+ audioMs,
273
+ realTimeFactor: audioMs > 0 ? (performance.now() - started) / audioMs : 0
274
+ });
275
+ return !readerSignal.aborted && sequence === this.sequence;
276
+ } catch (error) {
277
+ trace("error", {
278
+ aborted: readerSignal.aborted,
279
+ durationMs: performance.now() - started,
280
+ errorName: voiceDiagnosticError(error)
281
+ });
282
+ if (readerSignal.aborted || sequence !== this.sequence) return false;
283
+ this.cancel();
284
+ throw error;
285
+ }
286
+ }
287
+ /** 文本队列耗尽后再等音频播完;取消旧轮次不会误清理新轮次的请求。 */
288
+ async finish() {
289
+ const abort = this.abort;
290
+ if (abort === void 0) return true;
291
+ const sequence = this.sequence;
292
+ await this.waitUntil(() => this.sources.size === 0, abort.signal);
293
+ if (this.abort === abort) this.abort = void 0;
294
+ return !abort.signal.aborted && sequence === this.sequence;
295
+ }
296
+ cancel() {
297
+ this.sequence++;
298
+ this.abort?.abort();
299
+ this.abort = void 0;
300
+ for (const source of this.sources) {
301
+ source.onended = null;
302
+ try {
303
+ source.stop();
304
+ } catch {}
305
+ source.disconnect();
306
+ }
307
+ this.sources.clear();
308
+ this.nextStart = 0;
309
+ }
310
+ dispose() {
311
+ this.cancel();
312
+ this.gain?.disconnect();
313
+ this.gain = void 0;
314
+ const context = this.context;
315
+ this.context = void 0;
316
+ context?.close().catch(() => void 0);
317
+ }
318
+ enqueue(samples, sampleRate, rate, trace, first) {
319
+ const context = this.context;
320
+ if (this.nextStart - context.currentTime > 30) throw new Error("MOSS 播放队列过长,请缩短文本");
321
+ const buffer = context.createBuffer(1, samples.length, sampleRate);
322
+ buffer.copyToChannel(samples, 0);
323
+ const source = context.createBufferSource();
324
+ source.buffer = buffer;
325
+ source.playbackRate.value = rate;
326
+ source.connect(this.gain);
327
+ source.onended = () => {
328
+ this.sources.delete(source);
329
+ source.disconnect();
330
+ };
331
+ this.sources.add(source);
332
+ const start = Math.max(context.currentTime + .02, this.nextStart);
333
+ trace("playback_scheduled", {
334
+ gapMs: this.nextStart > 0 ? Math.max(0, context.currentTime - this.nextStart) * 1e3 : 0,
335
+ queueMs: (start - context.currentTime) * 1e3,
336
+ sourceCount: this.sources.size,
337
+ contextState: context.state,
338
+ muted: this.muted
339
+ });
340
+ if (first) trace("first_playback_scheduled", { queueMs: (start - context.currentTime) * 1e3 });
341
+ source.start(start);
342
+ this.nextStart = start + buffer.duration / rate;
343
+ }
344
+ async waitUntil(ready, signal) {
345
+ if (ready() || signal.aborted) return;
346
+ await new Promise((resolve) => {
347
+ let timer;
348
+ const finish = () => {
349
+ if (timer !== void 0) clearTimeout(timer);
350
+ signal.removeEventListener("abort", finish);
351
+ resolve();
352
+ };
353
+ const check = () => {
354
+ if (signal.aborted || ready()) finish();
355
+ else timer = setTimeout(check, 30);
356
+ };
357
+ signal.addEventListener("abort", finish, { once: true });
358
+ check();
359
+ });
360
+ }
361
+ };
362
+ /** PCM 固定为 48kHz、单声道、16 位小端,与 Host 工作进程协议一致。 */
363
+ function decodeMossPcm(event) {
364
+ if (event.sampleRate !== 48e3 || typeof event.data !== "string" || event.data.length > 1048576) throw new Error("Host TTS PCM 格式无效");
365
+ const raw = atob(event.data);
366
+ if (raw.length === 0 || raw.length % 2 !== 0) throw new Error("Host TTS PCM 长度无效");
367
+ const samples = new Float32Array(raw.length / 2);
368
+ for (let index = 0; index < samples.length; index++) {
369
+ const value = raw.charCodeAt(index * 2) | raw.charCodeAt(index * 2 + 1) << 8;
370
+ samples[index] = (value >= 32768 ? value - 65536 : value) / 32768;
371
+ }
372
+ return samples;
373
+ }
374
+ //#endregion
375
+ Object.defineProperty(exports, "MossVoiceOutput", {
376
+ enumerable: true,
377
+ get: function() {
378
+ return MossVoiceOutput;
379
+ }
380
+ });
381
+ Object.defineProperty(exports, "peerHostTagStyle", {
382
+ enumerable: true,
383
+ get: function() {
384
+ return peerHostTagStyle;
385
+ }
386
+ });
387
+ Object.defineProperty(exports, "resolvePeerHostColor", {
388
+ enumerable: true,
389
+ get: function() {
390
+ return resolvePeerHostColor;
391
+ }
392
+ });
393
+ Object.defineProperty(exports, "sanitizeVoiceDiagnosticFields", {
394
+ enumerable: true,
395
+ get: function() {
396
+ return sanitizeVoiceDiagnosticFields;
397
+ }
398
+ });
399
+ Object.defineProperty(exports, "voiceDiagnosticError", {
400
+ enumerable: true,
401
+ get: function() {
402
+ return voiceDiagnosticError;
403
+ }
404
+ });
405
+ Object.defineProperty(exports, "voiceDiagnosticId", {
406
+ enumerable: true,
407
+ get: function() {
408
+ return voiceDiagnosticId;
409
+ }
410
+ });
411
+ return module.exports;
412
+ }
413
+ });
414
+
415
+ //# sourceMappingURL=client.moss-voice-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.moss-voice-output.js","names":["normalizePeerHostColor","readAssistantTtsParameters","ASSISTANT_TTS_PATH"],"sources":["../../../../src/client/peer-host-color.ts","../../../../src/shared/voice-diagnostics.ts","../../../../src/client/moss-voice-output.ts"],"sourcesContent":["import { normalizePeerHostColor } from '../shared/contracts/peer-host.js'\nimport type { CSSProperties } from 'react'\n\n/**\n * 工作区标签配色的推导与缓存。\n *\n * 用户在 PeerHost 管理里显式配置的颜色优先;没有配置时按 Host 名称推导一个稳定\n * 颜色,保证同一台机器在多次刷新、多个工作区之间颜色一致——颜色本身是识别手段,\n * 随机色会让标签失去意义。\n */\n\n/** 无显式配色时使用的候选色板;与 PEER_HOST_COLOR_PRESETS 保持同一组观感。 */\nconst FALLBACK_PALETTE = [\n '#1677ff',\n '#722ed1',\n '#13c2c2',\n '#52c41a',\n '#fa8c16',\n '#eb2f96',\n '#f5222d',\n '#8c8c8c',\n] as const\n\nconst derivedCache = new Map<string, string>()\n\n/**\n * 解析某台 Host 的工作区标签颜色。\n *\n * @param explicit - 用户在 PeerHost 配置里保存的颜色;非法或缺省时走推导。\n * @param seed - 推导种子,通常用 PeerHost 名称;同一名称始终得到同一颜色。\n * @returns `#rrggbb` 形式的小写颜色。\n */\nexport function resolvePeerHostColor(explicit: string | null | undefined, seed: string): string {\n const configured = normalizePeerHostColor(explicit)\n if (configured !== null) return configured\n const key = seed.trim() === '' ? 'peer-host' : seed.trim()\n const cached = derivedCache.get(key)\n if (cached !== undefined) return cached\n const color = FALLBACK_PALETTE[hashString(key) % FALLBACK_PALETTE.length]!\n derivedCache.set(key, color)\n return color\n}\n\n/** FNV-1a 32 位哈希;只用于选色,不需要密码学强度。 */\nfunction hashString(value: string): number {\n let hash = 0x811c9dc5\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index)\n hash = Math.imul(hash, 0x01000193) >>> 0\n }\n return hash >>> 0\n}\n\n/** 标签胶囊的底色:与归档面板 Agent 徽标保持同一种 `color-mix` 写法。 */\nexport function peerHostTagBackground(color: string): string {\n return `color-mix(in srgb, ${color} 16%, transparent)`\n}\n\n/** 标签文字色;直接使用配置色,保证明暗主题下都有足够对比。 */\nexport function peerHostTagForeground(color: string): string {\n return color\n}\n\n/** 工作区列表与关联项目表共用的 Host 胶囊标签基础样式。 */\nexport function peerHostTagStyle(color: string): CSSProperties {\n return {\n boxSizing: 'border-box',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n padding: '1px 6px',\n borderRadius: '999px',\n fontSize: '10px',\n lineHeight: '1.5',\n pointerEvents: 'none',\n color: peerHostTagForeground(color),\n background: peerHostTagBackground(color),\n }\n}\n","/** 诊断只接收标量指标,禁止把音频、正文、提示词和认证信息写入日志。 */\nexport type VoiceDiagnosticFields = Readonly<Record<string, string | number | boolean | null | undefined>>\nexport type VoiceDiagnosticTrace = (event: string, fields?: VoiceDiagnosticFields) => void\nexport interface VoiceDiagnosticRecord {\n readonly timestamp: number\n readonly event: string\n readonly fields: VoiceDiagnosticFields\n}\n\nconst sinks = new Set<(record: VoiceDiagnosticRecord) => void>()\nconst allowedFields = new Set(`ownerId clientId callId requestId diagnosticId epoch sequence firstSequence lastSequence\n action state phase backend provider model code errorName status durationMs waitMs firstAudioMs firstTextMs\n firstSentenceMs firstPlaybackMs queueMs gapMs intervalMs maxIntervalMs processMs maxProcessMs decodeMs\n maxDecodeMs audioMs bytes pendingBytes pending frames chunks samples sampleRate inputRate threads tokens\n textLength systemLength messageCount toolCount count dropped stale aborted completed continuation muted\n sourceCount contextState processor cpuPercent rssMb heapMb eventLoopMeanMs eventLoopMaxMs eventLoopP99Ms\n realTimeFactor generationMs codecMs transportMs segment generationFrames fileIndex\n pcmBytes headerBytes pendingAudioMs inFlightMs endpointSilenceMs cached streaming\n webSearchAvailable searchRegistration`.split(/\\s+/u))\n\nexport function sanitizeVoiceDiagnosticFields(value: unknown): VoiceDiagnosticFields {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return {}\n const fields: Record<string, string | number | boolean | null> = {}\n for (const key of allowedFields) {\n const item = (value as Record<string, unknown>)[key]\n if (typeof item === 'number' && Number.isFinite(item) || typeof item === 'boolean' || item === null) fields[key] = item as number | boolean | null\n else if (typeof item === 'string') fields[key] = item.slice(0, 160)\n }\n return fields\n}\n\n/** 订阅函数异常不能进入语音业务链;未安装诊断时调用只做一次空集合检查。 */\nexport const traceVoice: VoiceDiagnosticTrace = (event, fields = {}) => {\n if (sinks.size === 0) return\n const record = { timestamp: Date.now(), event, fields: sanitizeVoiceDiagnosticFields(fields) }\n for (const sink of sinks) { try { sink(record) } catch { /* 诊断失败不影响通话 */ } }\n}\n\nexport function subscribeVoiceDiagnostics(sink: (record: VoiceDiagnosticRecord) => void): () => void {\n sinks.add(sink)\n return () => { sinks.delete(sink) }\n}\n\nexport function voiceDiagnosticsEnabled(): boolean { return sinks.size > 0 }\n\nexport function voiceDiagnosticId(): string { return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}` }\nexport function voiceDiagnosticError(error: unknown): string { return error instanceof Error ? error.name : 'UnknownError' }\n\n/** 单调时钟计时,系统时间校准不会造成负耗时。 */\nexport async function measureVoice<T>(event: string, fields: VoiceDiagnosticFields, operation: () => Promise<T>): Promise<T> {\n const started = performance.now()\n traceVoice(`${event}.start`, fields)\n try {\n const result = await operation()\n traceVoice(`${event}.done`, { ...fields, durationMs: performance.now() - started })\n return result\n } catch (error) {\n traceVoice(`${event}.error`, { ...fields, durationMs: performance.now() - started, errorName: voiceDiagnosticError(error) })\n throw error\n }\n}\n","import { ASSISTANT_TTS_PATH, readAssistantTtsParameters, type AssistantTtsParameters } from '../shared/assistant-tts.js'\nimport { voiceDiagnosticId, voiceDiagnosticError, type VoiceDiagnosticTrace, type VoiceDiagnosticFields } from '../shared/voice-diagnostics.js'\n\ntype SinkAudioContext = AudioContext & { setSinkId?: (id: string) => Promise<void> }\n\n/** 可取消的 PCM 播放器;同一轮的各段串行生成,生成与播放并行。 */\nexport class MossVoiceOutput {\n private context: SinkAudioContext | undefined\n private abort: AbortController | undefined\n private readonly sources = new Set<AudioBufferSourceNode>()\n private sequence = 0\n private outputDeviceId = ''\n private nextStart = 0\n private gain: GainNode | undefined\n private muted = false\n private volume = 1\n\n constructor(private readonly options: { fetch?: typeof fetch; context?: () => AudioContext; trace?: VoiceDiagnosticTrace; traceContext?: () => VoiceDiagnosticFields } = {}) {}\n\n get outputDeviceSupported(): boolean { return typeof (globalThis.AudioContext?.prototype as SinkAudioContext | undefined)?.setSinkId === 'function' }\n\n /** 在点击开始或试听时调用,保留浏览器要求的用户手势。 */\n async prepare(): Promise<void> {\n if (this.context === undefined || this.context.state === 'closed') this.context = (this.options.context?.() ?? new AudioContext()) as SinkAudioContext\n if (this.gain === undefined) { this.gain = this.context.createGain(); this.gain.gain.value = this.muted ? 0 : this.volume; this.gain.connect(this.context.destination) }\n if (this.context.state === 'suspended') await this.context.resume()\n if (this.outputDeviceId !== '' && typeof this.context.setSinkId === 'function') await this.context.setSinkId(this.outputDeviceId)\n }\n\n async setOutputDevice(id: string): Promise<void> {\n if (!this.outputDeviceSupported) throw new Error('当前浏览器不支持 MOSS 播放设备选择')\n if (this.context !== undefined) await this.context.setSinkId!(id)\n this.outputDeviceId = id\n }\n\n /** 输出静音不中断推理或时间线,恢复后继续听当前播报。 */\n setMuted(muted: boolean): void { this.muted = muted; if (this.gain !== undefined) this.gain.gain.value = muted ? 0 : this.volume }\n\n async speak(text: string, voiceId?: string, onStart?: () => void, parameters?: Partial<AssistantTtsParameters>): Promise<boolean> {\n this.cancel()\n const sequence = this.sequence\n if (!await this.append(text, voiceId, onStart, parameters) || sequence !== this.sequence) return false\n return this.finish()\n }\n\n /** 由文本队列串行调用;收到生成结束即可提交下一段,不取消仍在播放的前一段。 */\n async append(text: string, voiceId?: string, onStart?: () => void, parameters?: Partial<AssistantTtsParameters>): Promise<boolean> {\n const started = performance.now()\n const diagnosticId = voiceDiagnosticId()\n const fields: VoiceDiagnosticFields = { ...this.options.traceContext?.(), diagnosticId, textLength: text.length }\n const trace: VoiceDiagnosticTrace = (event, metrics) => this.options.trace?.(`client.tts.${event}`, { ...fields, ...metrics })\n let chunks = 0; let audioMs = 0; let lastChunkAt = started\n const playback = readAssistantTtsParameters(parameters)\n const sequence = this.sequence\n const continuation = this.abort !== undefined\n const abort = this.abort ?? new AbortController(); this.abort = abort\n const readerSignal = abort.signal\n trace('start', { continuation })\n try {\n await this.prepare()\n if (readerSignal.aborted) return false\n const queueStarted = performance.now()\n // 只提前准备有限音频;继续播放时逐步放行,仍只使用一个 Host 推理进程。\n await this.waitUntil(() => this.sources.size === 0 || this.nextStart - this.context!.currentTime <= 5, readerSignal)\n if (readerSignal.aborted) return false\n trace('queue_ready', { waitMs: performance.now() - queueStarted, queueMs: Math.max(0, this.nextStart - this.context!.currentTime) * 1000 })\n this.volume = playback.volume\n this.gain!.gain.value = this.muted ? 0 : this.volume\n const response = await (this.options.fetch ?? globalThis.fetch)(new URL(ASSISTANT_TTS_PATH, globalThis.location?.origin ?? 'http://localhost'), {\n method: 'POST', credentials: 'same-origin', signal: readerSignal,\n headers: { 'content-type': 'application/json', accept: 'application/x-ndjson' },\n body: JSON.stringify({ text, parameters: playback, diagnosticId, ...(voiceId === undefined ? {} : { voiceId }), ...(fields.requestId === undefined ? {} : { requestId: fields.requestId }), ...(fields.ownerId === undefined ? {} : { ownerId: fields.ownerId }) }),\n })\n trace('headers', { status: response.status, durationMs: performance.now() - started })\n if (!response.ok) {\n const value = await response.json().catch(() => ({})) as { error?: unknown }\n throw new Error(typeof value.error === 'string' ? value.error : `Host TTS 请求失败(${response.status})`)\n }\n if (response.body === null) throw new Error('Host TTS 响应缺少音频流')\n const reader = response.body.getReader(); const decoder = new TextDecoder()\n let buffer = ''; let completed = false; let played = false\n try {\n while (true) {\n const next = await reader.read()\n if (readerSignal.aborted) return false\n if (next.done) break\n buffer += decoder.decode(next.value, { stream: true })\n if (buffer.length > 2 * 1024 * 1024) throw new Error('Host TTS 音频事件过大')\n let boundary = buffer.indexOf('\\n')\n while (boundary >= 0) {\n const line = buffer.slice(0, boundary).trim(); buffer = buffer.slice(boundary + 1)\n if (line !== '') {\n const event = JSON.parse(line) as Record<string, unknown>\n if (completed) throw new Error('Host TTS 在完成后继续返回音频')\n if (event.type === 'error') throw new Error(String(event.message))\n if (event.type === 'done') completed = true\n else if (event.type === 'audio') {\n const arrived = performance.now()\n if (chunks === 0) trace('first_audio', { firstAudioMs: arrived - started })\n const samples = decodeMossPcm(event)\n const decodeMs = performance.now() - arrived\n chunks++; audioMs += samples.length / Number(event.sampleRate) * 1000\n trace('chunk', { chunks, decodeMs, samples: samples.length, audioMs: samples.length / Number(event.sampleRate) * 1000, intervalMs: arrived - lastChunkAt, queueMs: Math.max(0, this.nextStart - this.context!.currentTime) * 1000 })\n lastChunkAt = arrived\n if (!played && continuation) this.nextStart += playback.segmentPauseMs / 1000\n await this.waitUntil(() => this.sources.size === 0 || this.nextStart - this.context!.currentTime <= 5, readerSignal)\n if (readerSignal.aborted) return false\n this.enqueue(samples, Number(event.sampleRate), playback.rate, trace, chunks === 1 && !continuation)\n if (!played) { played = true; onStart?.() }\n } else throw new Error('Host TTS 返回未知事件')\n }\n boundary = buffer.indexOf('\\n')\n }\n }\n } finally { await reader.cancel().catch(() => undefined); reader.releaseLock() }\n if (!completed || !played || buffer.trim() !== '') throw new Error('Host TTS 音频流未完整结束')\n trace('generated', { durationMs: performance.now() - started, chunks, audioMs, realTimeFactor: audioMs > 0 ? (performance.now() - started) / audioMs : 0 })\n return !readerSignal.aborted && sequence === this.sequence\n } catch (error) {\n trace('error', { aborted: readerSignal.aborted, durationMs: performance.now() - started, errorName: voiceDiagnosticError(error) })\n if (readerSignal.aborted || sequence !== this.sequence) return false\n this.cancel()\n throw error\n }\n }\n\n /** 文本队列耗尽后再等音频播完;取消旧轮次不会误清理新轮次的请求。 */\n async finish(): Promise<boolean> {\n const abort = this.abort\n if (abort === undefined) return true\n const sequence = this.sequence\n await this.waitUntil(() => this.sources.size === 0, abort.signal)\n if (this.abort === abort) this.abort = undefined\n return !abort.signal.aborted && sequence === this.sequence\n }\n\n cancel(): void {\n this.sequence++; this.abort?.abort(); this.abort = undefined\n for (const source of this.sources) { source.onended = null; try { source.stop() } catch { /* 已经播放完 */ } source.disconnect() }\n this.sources.clear(); this.nextStart = 0\n }\n\n dispose(): void { this.cancel(); this.gain?.disconnect(); this.gain = undefined; const context = this.context; this.context = undefined; void context?.close().catch(() => undefined) }\n\n private enqueue(samples: Float32Array, sampleRate: number, rate: number, trace: VoiceDiagnosticTrace, first: boolean): void {\n const context = this.context!\n // 最多保留 30 秒待播音频,让异常快速生成也不能无限积压浏览器内存。\n if (this.nextStart - context.currentTime > 30) throw new Error('MOSS 播放队列过长,请缩短文本')\n const buffer = context.createBuffer(1, samples.length, sampleRate)\n buffer.copyToChannel(samples as Float32Array<ArrayBuffer>, 0)\n const source = context.createBufferSource(); source.buffer = buffer; source.playbackRate.value = rate; source.connect(this.gain!)\n source.onended = () => { this.sources.delete(source); source.disconnect() }\n this.sources.add(source)\n const start = Math.max(context.currentTime + 0.02, this.nextStart)\n const gapMs = this.nextStart > 0 ? Math.max(0, context.currentTime - this.nextStart) * 1000 : 0\n trace('playback_scheduled', { gapMs, queueMs: (start - context.currentTime) * 1000, sourceCount: this.sources.size, contextState: context.state, muted: this.muted })\n if (first) trace('first_playback_scheduled', { queueMs: (start - context.currentTime) * 1000 })\n // 后一块按实际变速后的时长接续,避免调快时留空隙、调慢时相互重叠。\n source.start(start); this.nextStart = start + buffer.duration / rate\n }\n\n private async waitUntil(ready: () => boolean, signal: AbortSignal): Promise<void> {\n if (ready() || signal.aborted) return\n await new Promise<void>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | undefined\n const finish = (): void => { if (timer !== undefined) clearTimeout(timer); signal.removeEventListener('abort', finish); resolve() }\n const check = (): void => { if (signal.aborted || ready()) finish(); else timer = setTimeout(check, 30) }\n signal.addEventListener('abort', finish, { once: true }); check()\n })\n }\n}\n\n/** PCM 固定为 48kHz、单声道、16 位小端,与 Host 工作进程协议一致。 */\nexport function decodeMossPcm(event: Record<string, unknown>): Float32Array {\n if (event.sampleRate !== 48_000 || typeof event.data !== 'string' || event.data.length > 1024 * 1024) throw new Error('Host TTS PCM 格式无效')\n const raw = atob(event.data)\n if (raw.length === 0 || raw.length % 2 !== 0) throw new Error('Host TTS PCM 长度无效')\n const samples = new Float32Array(raw.length / 2)\n for (let index = 0; index < samples.length; index++) {\n const value = raw.charCodeAt(index * 2) | raw.charCodeAt(index * 2 + 1) << 8\n samples[index] = (value >= 32768 ? value - 65536 : value) / 32768\n }\n return samples\n}\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
8
8
  const require_session_translation = require("@jingyi0605/codingns4dsh/client.session-translation.js");
9
9
  //#region src/shared/contracts/version.ts
10
10
  /** 当前经过完整验证的 DSH 版本;源文件由根目录 version.json 同步。 */
11
- const DSH_VERSION = "0.2.1-alpha.2";
11
+ const DSH_VERSION = "0.2.1-alpha.3";
12
12
  /**
13
13
  * 插件正式验证的 DSH 版本范围,覆盖 rc.2 到当前验证的 alpha.2。
14
14
  *
@@ -21,7 +21,7 @@ window.__ModuleLoader__.load({
21
21
  * 这里保留明确上界,是为了让 npm/DSH 安装期也能识别 0.2.1-alpha.2 这个跨 patch
22
22
  * 预发布版本;出现新的 API 世代或结构变化时,应重新验证并更新范围与能力路由。
23
23
  */
24
- const DSH_COMPATIBILITY = ">=0.2.0-rc.2 <=0.2.1-alpha.2";
24
+ const DSH_COMPATIBILITY = ">=0.2.0-rc.2 <=0.2.1-alpha.3";
25
25
  /**
26
26
  * 兼容范围下界,即插件仍然接受的最低 DSH 版本。
27
27
  *
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
30
30
  * “不支持的 DSH 版本”,把仅仅缺少启动页注入的页面误判为宿主不兼容。
31
31
  */
32
32
  function minimumSupportedDshVersion() {
33
- return /^>=([^ ]+)/u.exec(">=0.2.0-rc.2 <=0.2.1-alpha.2")?.[1] ?? "0.2.1-alpha.2";
33
+ return /^>=([^ ]+)/u.exec(">=0.2.0-rc.2 <=0.2.1-alpha.3")?.[1] ?? "0.2.1-alpha.3";
34
34
  }
35
35
  /** Host 注入到浏览器页面的真实 DSH 版本全局字段。 */
36
36
  const CODINGNS_DSH_VERSION_GLOBAL = "__CODINGNS_DSH_VERSION__";
@@ -39,7 +39,7 @@ window.__ModuleLoader__.load({
39
39
  return /^0\.1\.5(?:-|$)/u.test(version);
40
40
  }
41
41
  /** Codingns4DSH 插件自身的 npm 版本。 */
42
- const CODINGNS_VERSION = "0.2.1-beta.10";
42
+ const CODINGNS_VERSION = "0.2.1-beta.12";
43
43
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
44
44
  function isDshVersionCompatible(version) {
45
45
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);