@flowingspring/dsh-voco 0.2.6 → 0.2.7

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.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 QUAN
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 QUAN
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,56 +1,56 @@
1
- # `@flowingspring/dsh-voco`
2
-
3
- [![npm version](https://img.shields.io/npm/v/@flowingspring/dsh-voco.svg)](https://www.npmjs.com/package/@flowingspring/dsh-voco)
4
- [![license](https://img.shields.io/npm/l/@flowingspring/dsh-voco.svg)](https://github.com/lgquan/dsh-voco/blob/master/LICENSE)
5
-
6
- English | [中文](README.zh.md)
7
-
8
- Persistent, interruptible voice conversations for the DSH Web UI. Speak naturally, get an immediate conversational response, and delegate workspace tasks to a durable background Agent Session without losing context.
9
-
10
- ## Install
11
-
12
- ```sh
13
- dsh plugin --profile web add @flowingspring/dsh-voco
14
- dsh web
15
- ```
16
-
17
- Install the DSH CLI first if needed:
18
-
19
- ```sh
20
- npm install -g @deepseek-ai/dsh
21
- ```
22
-
23
- ## Configure speech recognition
24
-
25
- Set a [SiliconFlow](https://siliconflow.cn/) API key in the DSH environment:
26
-
27
- ```dotenv
28
- SILICONFLOW_API_KEY=your-key
29
- ```
30
-
31
- The plugin uses `XingChenAGI/XingChenASR-V3.2-Ultra` for cloud speech recognition and Edge TTS with `zh-CN-XiaoxiaoNeural` for speech output. Browser audio is uploaded only after lightweight local speech and silence detection.
32
-
33
- ## Highlights
34
-
35
- - Keeps one background Agent Session bound to each Voice Session, including after DSH restarts.
36
- - Answers ordinary conversation directly and delegates only work that needs tools.
37
- - Speaks a short contextual acknowledgement before starting delegated Agent work.
38
- - Keeps full task reports in the task UI while speaking a concise, purpose-written result.
39
- - Supports interruption, browser navigation, reconnects, and restored conversation history.
40
- - Ships the server and browser surfaces as one public npm package.
41
-
42
- ## Configuration
43
-
44
- The default utterance boundary is 1.5 seconds of continuous silence. Advanced settings such as `silenceDurationMs`, `speechThreshold`, `minSpeechDurationMs`, and `maxUtteranceMs` are available in the plugin profile configuration.
45
-
46
- ## Requirements and limitations
47
-
48
- - The microphone and playback surface targets the DSH Web UI and is not a framework-independent browser plugin.
49
- - Speech recognition requires network access and a SiliconFlow API key.
50
- - Voice responses currently use the Chinese Xiaoxiao Edge TTS voice by default.
51
-
52
- Source, development instructions, and issue tracking are available in the [GitHub repository](https://github.com/lgquan/dsh-voco).
53
-
54
- ## License
55
-
56
- [MIT](LICENSE)
1
+ # `@flowingspring/dsh-voco`
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@flowingspring/dsh-voco.svg)](https://www.npmjs.com/package/@flowingspring/dsh-voco)
4
+ [![license](https://img.shields.io/npm/l/@flowingspring/dsh-voco.svg)](https://github.com/lgquan/dsh-voco/blob/master/LICENSE)
5
+
6
+ English | [中文](README.zh.md)
7
+
8
+ Persistent, interruptible voice conversations for the DSH Web UI. Speak naturally, get an immediate conversational response, and delegate workspace tasks to a durable background Agent Session without losing context.
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ dsh plugin --profile web add @flowingspring/dsh-voco
14
+ dsh web
15
+ ```
16
+
17
+ Install the DSH CLI first if needed:
18
+
19
+ ```sh
20
+ npm install -g @deepseek-ai/dsh
21
+ ```
22
+
23
+ ## Configure speech recognition
24
+
25
+ Set a [SiliconFlow](https://siliconflow.cn/) API key in the DSH environment:
26
+
27
+ ```dotenv
28
+ SILICONFLOW_API_KEY=your-key
29
+ ```
30
+
31
+ The plugin uses `XingChenAGI/XingChenASR-V3.2-Ultra` for cloud speech recognition and Edge TTS with `zh-CN-XiaoxiaoNeural` for speech output. Browser audio is uploaded only after lightweight local speech and silence detection.
32
+
33
+ ## Highlights
34
+
35
+ - Keeps one background Agent Session bound to each Voice Session, including after DSH restarts.
36
+ - Answers ordinary conversation directly and delegates only work that needs tools.
37
+ - Speaks a short contextual acknowledgement before starting delegated Agent work.
38
+ - Keeps full task reports in the task UI while speaking a concise, purpose-written result.
39
+ - Supports interruption, browser navigation, reconnects, and restored conversation history.
40
+ - Ships the server and browser surfaces as one public npm package.
41
+
42
+ ## Configuration
43
+
44
+ The default utterance boundary is 1.5 seconds of continuous silence. Advanced settings such as `silenceDurationMs`, `speechThreshold`, `minSpeechDurationMs`, and `maxUtteranceMs` are available in the plugin profile configuration.
45
+
46
+ ## Requirements and limitations
47
+
48
+ - The microphone and playback surface targets the DSH Web UI and is not a framework-independent browser plugin.
49
+ - Speech recognition requires network access and a SiliconFlow API key.
50
+ - Voice responses currently use the Chinese Xiaoxiao Edge TTS voice by default.
51
+
52
+ Source, development instructions, and issue tracking are available in the [GitHub repository](https://github.com/lgquan/dsh-voco).
53
+
54
+ ## License
55
+
56
+ [MIT](LICENSE)
package/README.zh.md CHANGED
@@ -1,56 +1,56 @@
1
- # `@flowingspring/dsh-voco`
2
-
3
- [![npm version](https://img.shields.io/npm/v/@flowingspring/dsh-voco.svg)](https://www.npmjs.com/package/@flowingspring/dsh-voco)
4
- [![许可证](https://img.shields.io/npm/l/@flowingspring/dsh-voco.svg)](https://github.com/lgquan/dsh-voco/blob/master/LICENSE)
5
-
6
- [English](README.md) | 中文
7
-
8
- 面向 DSH Web UI 的可恢复、可打断语音对话插件。你可以自然说出需求、立即获得口语回复,并把需要工具的工作委派给持续复用的后台 Agent Session,而不会丢失任务上下文。
9
-
10
- ## 安装
11
-
12
- ```sh
13
- dsh plugin --profile web add @flowingspring/dsh-voco
14
- dsh web
15
- ```
16
-
17
- 如果尚未安装 DSH 命令行:
18
-
19
- ```sh
20
- npm install -g @deepseek-ai/dsh
21
- ```
22
-
23
- ## 配置语音识别
24
-
25
- 在 DSH 的运行环境中设置[硅基流动](https://siliconflow.cn/) API Key:
26
-
27
- ```dotenv
28
- SILICONFLOW_API_KEY=你的密钥
29
- ```
30
-
31
- 插件使用 `XingChenAGI/XingChenASR-V3.2-Ultra` 完成云端语音识别,并通过 Edge TTS 的 `zh-CN-XiaoxiaoNeural` 音色输出语音。浏览器只在本地做轻量起音和静音检测,确认一句话结束后才上传音频。
32
-
33
- ## 主要功能
34
-
35
- - 每个 Voice Session 持续绑定一个后台 Agent Session,重启 DSH 后也能恢复。
36
- - 普通聊天直接回答,只有需要工具的工作才委派给后台 Agent。
37
- - 委派任务启动前立即播报一句贴合当前请求的简短确认语。
38
- - 完整任务报告保留在任务界面,语音只播报专门生成的简洁结果。
39
- - 支持语音打断、页面切换、断线重连以及历史对话恢复。
40
- - 服务端和浏览器界面统一通过一个公开 npm 包发行。
41
-
42
- ## 配置项
43
-
44
- 默认以连续静音 1.5 秒作为一句话的边界。`silenceDurationMs`、`speechThreshold`、`minSpeechDurationMs` 和 `maxUtteranceMs` 等高级参数可在插件 profile 配置中调整。
45
-
46
- ## 要求与限制
47
-
48
- - 麦克风和播放界面面向 DSH Web UI,并不是框架无关的浏览器插件。
49
- - 云端语音识别需要网络连接及硅基流动 API Key。
50
- - 语音回复目前默认使用 Edge TTS 的中文晓晓音色。
51
-
52
- 源码、开发说明和问题反馈请前往 [GitHub 仓库](https://github.com/lgquan/dsh-voco)。
53
-
54
- ## 许可证
55
-
56
- [MIT](LICENSE)
1
+ # `@flowingspring/dsh-voco`
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@flowingspring/dsh-voco.svg)](https://www.npmjs.com/package/@flowingspring/dsh-voco)
4
+ [![许可证](https://img.shields.io/npm/l/@flowingspring/dsh-voco.svg)](https://github.com/lgquan/dsh-voco/blob/master/LICENSE)
5
+
6
+ [English](README.md) | 中文
7
+
8
+ 面向 DSH Web UI 的可恢复、可打断语音对话插件。你可以自然说出需求、立即获得口语回复,并把需要工具的工作委派给持续复用的后台 Agent Session,而不会丢失任务上下文。
9
+
10
+ ## 安装
11
+
12
+ ```sh
13
+ dsh plugin --profile web add @flowingspring/dsh-voco
14
+ dsh web
15
+ ```
16
+
17
+ 如果尚未安装 DSH 命令行:
18
+
19
+ ```sh
20
+ npm install -g @deepseek-ai/dsh
21
+ ```
22
+
23
+ ## 配置语音识别
24
+
25
+ 在 DSH 的运行环境中设置[硅基流动](https://siliconflow.cn/) API Key:
26
+
27
+ ```dotenv
28
+ SILICONFLOW_API_KEY=你的密钥
29
+ ```
30
+
31
+ 插件使用 `XingChenAGI/XingChenASR-V3.2-Ultra` 完成云端语音识别,并通过 Edge TTS 的 `zh-CN-XiaoxiaoNeural` 音色输出语音。浏览器只在本地做轻量起音和静音检测,确认一句话结束后才上传音频。
32
+
33
+ ## 主要功能
34
+
35
+ - 每个 Voice Session 持续绑定一个后台 Agent Session,重启 DSH 后也能恢复。
36
+ - 普通聊天直接回答,只有需要工具的工作才委派给后台 Agent。
37
+ - 委派任务启动前立即播报一句贴合当前请求的简短确认语。
38
+ - 完整任务报告保留在任务界面,语音只播报专门生成的简洁结果。
39
+ - 支持语音打断、页面切换、断线重连以及历史对话恢复。
40
+ - 服务端和浏览器界面统一通过一个公开 npm 包发行。
41
+
42
+ ## 配置项
43
+
44
+ 默认以连续静音 1.5 秒作为一句话的边界。`silenceDurationMs`、`speechThreshold`、`minSpeechDurationMs` 和 `maxUtteranceMs` 等高级参数可在插件 profile 配置中调整。
45
+
46
+ ## 要求与限制
47
+
48
+ - 麦克风和播放界面面向 DSH Web UI,并不是框架无关的浏览器插件。
49
+ - 云端语音识别需要网络连接及硅基流动 API Key。
50
+ - 语音回复目前默认使用 Edge TTS 的中文晓晓音色。
51
+
52
+ 源码、开发说明和问题反馈请前往 [GitHub 仓库](https://github.com/lgquan/dsh-voco)。
53
+
54
+ ## 许可证
55
+
56
+ [MIT](LICENSE)
package/cordis.patch.yml CHANGED
@@ -1,15 +1,15 @@
1
1
  # Voice interaction mode layered after dsh-base and dsh-web-app.
2
2
  - insert:
3
- - id: llm-tool-call-compat
4
- name: '@flowingspring/dsh-voco/llm-tool-call-compat'
5
-
6
- - id: voice
7
- name: '@flowingspring/dsh-voco/voice'
3
+ - id: llm-tool-call-compat
4
+ name: '@flowingspring/dsh-voco/llm-tool-call-compat'
5
+
6
+ - id: voice
7
+ name: '@flowingspring/dsh-voco/voice'
8
8
  config:
9
9
  provider: local
10
10
 
11
- - id: voice-local
12
- name: '@flowingspring/dsh-voco/voice-local'
11
+ - id: voice-local
12
+ name: '@flowingspring/dsh-voco/voice-local'
13
13
  config:
14
14
  interactionMode: frontend-agent
15
15
  inputSampleRate: 16000
@@ -20,8 +20,8 @@
20
20
  minSpeechDurationMs: 250
21
21
  maxUtteranceMs: 60000
22
22
 
23
- - id: voice-assistant
24
- name: '@flowingspring/dsh-voco/voice-assistant'
23
+ - id: voice-assistant
24
+ name: '@flowingspring/dsh-voco/voice-assistant'
25
25
  config:
26
26
  maxPendingObservations: 64
27
27
  restoreConversation: true
@@ -32,12 +32,12 @@
32
32
  cancelledAnnouncement: 任务已取消。
33
33
  interruptedAnnouncement: 上次任务因服务关闭而中断,没有自动重放。你可以告诉我是否继续。
34
34
 
35
- - id: voice-web
36
- name: '@flowingspring/dsh-voco/voice-web'
35
+ - id: voice-web
36
+ name: '@flowingspring/dsh-voco/voice-web'
37
37
  inject: [webRuntime]
38
38
  config:
39
39
  trustedHosts: !!js ctx.webRuntime.trustedHosts
40
40
  maxAudioFrameBytes: 65536
41
41
 
42
- - id: ui-voice
43
- name: '@flowingspring/dsh-voco'
42
+ - id: ui-voice
43
+ name: '@flowingspring/dsh-voco'
package/lib/client.js CHANGED
@@ -7,20 +7,20 @@ window.__ModuleLoader__.load({
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let react = require("react");
9
9
  let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
10
- //#region \0dsh-css:C:\Users\QUAN\AppData\Local\Temp\dsh-voco-release-0.2.6\packages\ui-voice\src\client\VoiceControl.module.css.mjs
11
- const css$3 = "._KsGSG_button{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}._KsGSG_button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._KsGSG_active{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover-solid)}._KsGSG_button[data-muted=true]{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, currentColor 12%, transparent)}._KsGSG_button[data-muted=true]:hover{background:color-mix(in srgb, currentColor 18%, transparent)}._KsGSG_button[data-state=speaking][data-muted=false]{animation:1.2s ease-in-out infinite _KsGSG_voice-pulse}@keyframes _KsGSG_voice-pulse{50%{opacity:.55;transform:scale(.94)}}@media (prefers-reduced-motion:reduce){._KsGSG_button[data-state=speaking][data-muted=false]{animation:none}}";
12
- const tagId$3 = "@flowingspring/dsh-voco/VoiceControl.module.css";
13
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
10
+ //#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceControl.module.css.mjs
11
+ const css$4 = ".TFZsua_button{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.TFZsua_button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.TFZsua_active{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover-solid)}.TFZsua_button[data-muted=true]{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, currentColor 12%, transparent)}.TFZsua_button[data-muted=true]:hover{background:color-mix(in srgb, currentColor 18%, transparent)}.TFZsua_button[data-state=speaking][data-muted=false]{animation:1.2s ease-in-out infinite TFZsua_voice-pulse}@keyframes TFZsua_voice-pulse{50%{opacity:.55;transform:scale(.94)}}@media (prefers-reduced-motion:reduce){.TFZsua_button[data-state=speaking][data-muted=false]{animation:none}}";
12
+ const tagId$4 = "@flowingspring/dsh-voco/VoiceControl.module.css";
13
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
14
14
  const tag = document.createElement("style");
15
15
  tag.dataset.plugin = "@flowingspring/dsh-voco";
16
- tag.dataset.pluginCss = tagId$3;
17
- tag.textContent = css$3;
16
+ tag.dataset.pluginCss = tagId$4;
17
+ tag.textContent = css$4;
18
18
  document.head.appendChild(tag);
19
19
  }
20
20
  var VoiceControl_module_css_default = {
21
- "button": "_KsGSG_button",
22
- "active": "_KsGSG_active",
23
- "voice-pulse": "_KsGSG_voice-pulse"
21
+ "button": "TFZsua_button",
22
+ "voice-pulse": "TFZsua_voice-pulse",
23
+ "active": "TFZsua_active"
24
24
  };
25
25
  //#endregion
26
26
  //#region ../ui-voice/src/client/VoiceControl.tsx
@@ -92,28 +92,28 @@ window.__ModuleLoader__.load({
92
92
  });
93
93
  }
94
94
  //#endregion
95
- //#region \0dsh-css:C:\Users\QUAN\AppData\Local\Temp\dsh-voco-release-0.2.6\packages\ui-voice\src\client\VoiceHistoryAction.module.css.mjs
96
- const css$2 = ".t7DtJW_trigger{width:100%;min-height:36px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;gap:9px;display:flex}.t7DtJW_trigger:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.t7DtJW_panel{z-index:60;border:1px solid var(--dsw-alias-border-l2);width:min(320px,100vw - 32px);max-height:min(480px,100vh - 96px);color:var(--dsw-alias-label-primary);background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);border-radius:14px;flex-direction:column;display:flex;position:fixed;bottom:64px;left:16px;overflow:hidden}.t7DtJW_header{border-bottom:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;min-height:48px;padding:0 12px 0 16px;display:flex}.t7DtJW_close{width:28px;height:28px;color:inherit;cursor:pointer;background:0 0;border:0;border-radius:7px;font-size:20px;line-height:1}.t7DtJW_close:hover{background:var(--dsw-alias-interactive-bg-hover)}.t7DtJW_list{padding:8px;overflow:auto}.t7DtJW_empty{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;padding:24px 12px;font-size:13px}.t7DtJW_row{width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:9px;align-items:center;gap:10px;padding:10px;display:flex}.t7DtJW_row:hover,.t7DtJW_row[data-active=true]{background:var(--dsw-alias-interactive-bg-hover)}.t7DtJW_wave{width:24px;height:24px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, currentColor 10%, transparent);border-radius:50%;flex:none;justify-content:center;align-items:center;gap:2px;display:flex}.t7DtJW_wave i{background:currentColor;border-radius:2px;width:2px}.t7DtJW_wave i:first-child{height:6px}.t7DtJW_wave i:nth-child(2){height:11px}.t7DtJW_wave i:nth-child(3){height:8px}.t7DtJW_rowText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.t7DtJW_title{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;overflow:hidden}.t7DtJW_meta{color:var(--dsw-alias-label-tertiary);font-size:11px}";
97
- const tagId$2 = "@flowingspring/dsh-voco/VoiceHistoryAction.module.css";
98
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
95
+ //#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceHistoryAction.module.css.mjs
96
+ const css$3 = "._3t8AFq_trigger{width:100%;min-height:36px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;gap:9px;display:flex}._3t8AFq_trigger:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._3t8AFq_panel{z-index:60;border:1px solid var(--dsw-alias-border-l2);width:min(320px,100vw - 32px);max-height:min(480px,100vh - 96px);color:var(--dsw-alias-label-primary);background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);border-radius:14px;flex-direction:column;display:flex;position:fixed;bottom:64px;left:16px;overflow:hidden}._3t8AFq_header{border-bottom:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;min-height:48px;padding:0 12px 0 16px;display:flex}._3t8AFq_close{width:28px;height:28px;color:inherit;cursor:pointer;background:0 0;border:0;border-radius:7px;font-size:20px;line-height:1}._3t8AFq_close:hover{background:var(--dsw-alias-interactive-bg-hover)}._3t8AFq_list{padding:8px;overflow:auto}._3t8AFq_empty{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;padding:24px 12px;font-size:13px}._3t8AFq_row{width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:9px;align-items:center;gap:10px;padding:10px;display:flex}._3t8AFq_row:hover,._3t8AFq_row[data-active=true]{background:var(--dsw-alias-interactive-bg-hover)}._3t8AFq_wave{width:24px;height:24px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, currentColor 10%, transparent);border-radius:50%;flex:none;justify-content:center;align-items:center;gap:2px;display:flex}._3t8AFq_wave i{background:currentColor;border-radius:2px;width:2px}._3t8AFq_wave i:first-child{height:6px}._3t8AFq_wave i:nth-child(2){height:11px}._3t8AFq_wave i:nth-child(3){height:8px}._3t8AFq_rowText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}._3t8AFq_title{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;overflow:hidden}._3t8AFq_meta{color:var(--dsw-alias-label-tertiary);font-size:11px}";
97
+ const tagId$3 = "@flowingspring/dsh-voco/VoiceHistoryAction.module.css";
98
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
99
99
  const tag = document.createElement("style");
100
100
  tag.dataset.plugin = "@flowingspring/dsh-voco";
101
- tag.dataset.pluginCss = tagId$2;
102
- tag.textContent = css$2;
101
+ tag.dataset.pluginCss = tagId$3;
102
+ tag.textContent = css$3;
103
103
  document.head.appendChild(tag);
104
104
  }
105
105
  var VoiceHistoryAction_module_css_default = {
106
- "rowText": "t7DtJW_rowText",
107
- "empty": "t7DtJW_empty",
108
- "panel": "t7DtJW_panel",
109
- "row": "t7DtJW_row",
110
- "close": "t7DtJW_close",
111
- "header": "t7DtJW_header",
112
- "list": "t7DtJW_list",
113
- "title": "t7DtJW_title",
114
- "wave": "t7DtJW_wave",
115
- "trigger": "t7DtJW_trigger",
116
- "meta": "t7DtJW_meta"
106
+ "trigger": "_3t8AFq_trigger",
107
+ "panel": "_3t8AFq_panel",
108
+ "list": "_3t8AFq_list",
109
+ "row": "_3t8AFq_row",
110
+ "rowText": "_3t8AFq_rowText",
111
+ "title": "_3t8AFq_title",
112
+ "meta": "_3t8AFq_meta",
113
+ "close": "_3t8AFq_close",
114
+ "empty": "_3t8AFq_empty",
115
+ "header": "_3t8AFq_header",
116
+ "wave": "_3t8AFq_wave"
117
117
  };
118
118
  //#endregion
119
119
  //#region ../ui-voice/src/client/VoiceHistoryAction.tsx
@@ -214,34 +214,34 @@ window.__ModuleLoader__.load({
214
214
  })] });
215
215
  }
216
216
  //#endregion
217
- //#region \0dsh-css:C:\Users\QUAN\AppData\Local\Temp\dsh-voco-release-0.2.6\packages\ui-voice\src\client\VoiceNodeViews.module.css.mjs
218
- const css$1 = ".SD91zq_utterance{flex-direction:column;align-items:flex-start;gap:6px;min-width:0;display:flex}.SD91zq_utterance[data-role=user]{align-items:flex-end}.SD91zq_bubble{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);max-width:min(525px,82%);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;white-space:pre-wrap;border-radius:18px;padding:10px 16px;font-size:16px;line-height:24px}.SD91zq_utterance[data-role=user] .SD91zq_bubble{background:var(--dsw-specific-bubble);border-color:#0000}.SD91zq_utterance[data-state=streaming] .SD91zq_bubble{color:var(--dsw-alias-label-secondary)}.SD91zq_meta,.SD91zq_voiceBadge{align-items:center;display:inline-flex}.SD91zq_meta{color:var(--dsw-alias-label-tertiary);gap:8px;padding:0 5px;font-size:10px;line-height:14px}.SD91zq_voiceBadge{color:var(--dsw-alias-state-business-primary);letter-spacing:.04em;gap:4px;font-weight:600}.SD91zq_miniWave{align-items:center;gap:1px;height:10px;display:inline-flex}.SD91zq_miniWave i{background:currentColor;border-radius:1px;width:1.5px;height:4px}.SD91zq_miniWave i:nth-child(2){height:8px}.SD91zq_miniWave i:nth-child(3){height:6px}.SD91zq_taskCard{box-sizing:border-box;width:fit-content;min-width:0;max-width:min(525px,100%)}.SD91zq_taskSummary{min-width:0;max-width:100%;color:inherit;cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;align-items:center;gap:7px;margin:-3px -5px;padding:3px 5px;display:inline-flex}.SD91zq_taskSummary:hover{background:var(--dsw-alias-bg-layer-1)}.SD91zq_taskDot{background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:7px;height:7px}.SD91zq_taskCard[data-status=completed] .SD91zq_taskDot{background:var(--dsw-alias-state-success-primary)}.SD91zq_taskCard[data-status=failed] .SD91zq_taskDot{background:var(--dsw-alias-state-error-primary)}.SD91zq_taskCard[data-status=cancelled] .SD91zq_taskDot,.SD91zq_taskCard[data-status=interrupted] .SD91zq_taskDot{background:var(--dsw-alias-state-warn-primary)}.SD91zq_taskTitle{min-width:0;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}.SD91zq_taskStatus{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.SD91zq_taskStatus:before{content:\"·\";margin-right:7px}.SD91zq_taskChevron{border-right:1px solid var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin:0 2px 0 1px;transition:transform .12s;transform:rotate(-45deg)}.SD91zq_taskCard[data-expanded=true] .SD91zq_taskChevron{transform:rotate(45deg)}.SD91zq_taskInput,.SD91zq_taskUpdate{overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.SD91zq_taskInput{color:var(--dsw-alias-label-primary)}.SD91zq_taskUpdate{color:var(--dsw-alias-label-secondary);margin-top:4px}.SD91zq_taskDetails{border-left:1px solid var(--dsw-alias-border-l2);margin:9px 0 0 3px;padding:2px 0 2px 16px}.SD91zq_taskActions{align-items:center;gap:14px;margin-top:7px;display:flex}.SD91zq_taskLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:18px}.SD91zq_taskLink:hover:not(:disabled){text-underline-position:from-font;text-decoration:underline}.SD91zq_taskLink:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.SD91zq_taskCancel{color:var(--dsw-alias-state-error-primary)}";
219
- const tagId$1 = "@flowingspring/dsh-voco/VoiceNodeViews.module.css";
220
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
217
+ //#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceNodeViews.module.css.mjs
218
+ const css$2 = ".Kt2smW_utterance{flex-direction:column;align-items:flex-start;gap:6px;min-width:0;display:flex}.Kt2smW_utterance[data-role=user]{align-items:flex-end}.Kt2smW_bubble{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);max-width:min(525px,82%);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;white-space:pre-wrap;border-radius:18px;padding:10px 16px;font-size:16px;line-height:24px}.Kt2smW_utterance[data-role=user] .Kt2smW_bubble{background:var(--dsw-specific-bubble);border-color:#0000}.Kt2smW_utterance[data-state=streaming] .Kt2smW_bubble{color:var(--dsw-alias-label-secondary)}.Kt2smW_meta,.Kt2smW_voiceBadge{align-items:center;display:inline-flex}.Kt2smW_meta{color:var(--dsw-alias-label-tertiary);gap:8px;padding:0 5px;font-size:10px;line-height:14px}.Kt2smW_voiceBadge{color:var(--dsw-alias-state-business-primary);letter-spacing:.04em;gap:4px;font-weight:600}.Kt2smW_miniWave{align-items:center;gap:1px;height:10px;display:inline-flex}.Kt2smW_miniWave i{background:currentColor;border-radius:1px;width:1.5px;height:4px}.Kt2smW_miniWave i:nth-child(2){height:8px}.Kt2smW_miniWave i:nth-child(3){height:6px}.Kt2smW_taskCard{box-sizing:border-box;width:fit-content;min-width:0;max-width:min(525px,100%)}.Kt2smW_taskSummary{min-width:0;max-width:100%;color:inherit;cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;align-items:center;gap:7px;margin:-3px -5px;padding:3px 5px;display:inline-flex}.Kt2smW_taskSummary:hover{background:var(--dsw-alias-bg-layer-1)}.Kt2smW_taskDot{background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:7px;height:7px}.Kt2smW_taskCard[data-status=completed] .Kt2smW_taskDot{background:var(--dsw-alias-state-success-primary)}.Kt2smW_taskCard[data-status=failed] .Kt2smW_taskDot{background:var(--dsw-alias-state-error-primary)}.Kt2smW_taskCard[data-status=cancelled] .Kt2smW_taskDot,.Kt2smW_taskCard[data-status=interrupted] .Kt2smW_taskDot{background:var(--dsw-alias-state-warn-primary)}.Kt2smW_taskTitle{min-width:0;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}.Kt2smW_taskStatus{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.Kt2smW_taskStatus:before{content:\"·\";margin-right:7px}.Kt2smW_taskChevron{border-right:1px solid var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin:0 2px 0 1px;transition:transform .12s;transform:rotate(-45deg)}.Kt2smW_taskCard[data-expanded=true] .Kt2smW_taskChevron{transform:rotate(45deg)}.Kt2smW_taskInput,.Kt2smW_taskUpdate{overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.Kt2smW_taskInput{color:var(--dsw-alias-label-primary)}.Kt2smW_taskUpdate{color:var(--dsw-alias-label-secondary);margin-top:4px}.Kt2smW_taskDetails{border-left:1px solid var(--dsw-alias-border-l2);margin:9px 0 0 3px;padding:2px 0 2px 16px}.Kt2smW_taskActions{align-items:center;gap:14px;margin-top:7px;display:flex}.Kt2smW_taskLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:18px}.Kt2smW_taskLink:hover:not(:disabled){text-underline-position:from-font;text-decoration:underline}.Kt2smW_taskLink:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Kt2smW_taskCancel{color:var(--dsw-alias-state-error-primary)}";
219
+ const tagId$2 = "@flowingspring/dsh-voco/VoiceNodeViews.module.css";
220
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
221
221
  const tag = document.createElement("style");
222
222
  tag.dataset.plugin = "@flowingspring/dsh-voco";
223
- tag.dataset.pluginCss = tagId$1;
224
- tag.textContent = css$1;
223
+ tag.dataset.pluginCss = tagId$2;
224
+ tag.textContent = css$2;
225
225
  document.head.appendChild(tag);
226
226
  }
227
227
  var VoiceNodeViews_module_css_default = {
228
- "taskInput": "SD91zq_taskInput",
229
- "voiceBadge": "SD91zq_voiceBadge",
230
- "taskDetails": "SD91zq_taskDetails",
231
- "miniWave": "SD91zq_miniWave",
232
- "taskCard": "SD91zq_taskCard",
233
- "taskUpdate": "SD91zq_taskUpdate",
234
- "utterance": "SD91zq_utterance",
235
- "taskStatus": "SD91zq_taskStatus",
236
- "taskCancel": "SD91zq_taskCancel",
237
- "taskTitle": "SD91zq_taskTitle",
238
- "taskChevron": "SD91zq_taskChevron",
239
- "meta": "SD91zq_meta",
240
- "taskLink": "SD91zq_taskLink",
241
- "taskDot": "SD91zq_taskDot",
242
- "taskSummary": "SD91zq_taskSummary",
243
- "bubble": "SD91zq_bubble",
244
- "taskActions": "SD91zq_taskActions"
228
+ "meta": "Kt2smW_meta",
229
+ "bubble": "Kt2smW_bubble",
230
+ "taskChevron": "Kt2smW_taskChevron",
231
+ "taskLink": "Kt2smW_taskLink",
232
+ "taskTitle": "Kt2smW_taskTitle",
233
+ "taskUpdate": "Kt2smW_taskUpdate",
234
+ "taskCard": "Kt2smW_taskCard",
235
+ "taskCancel": "Kt2smW_taskCancel",
236
+ "utterance": "Kt2smW_utterance",
237
+ "taskStatus": "Kt2smW_taskStatus",
238
+ "voiceBadge": "Kt2smW_voiceBadge",
239
+ "taskDot": "Kt2smW_taskDot",
240
+ "taskInput": "Kt2smW_taskInput",
241
+ "taskActions": "Kt2smW_taskActions",
242
+ "taskSummary": "Kt2smW_taskSummary",
243
+ "taskDetails": "Kt2smW_taskDetails",
244
+ "miniWave": "Kt2smW_miniWave"
245
245
  };
246
246
  //#endregion
247
247
  //#region ../ui-voice/src/client/VoiceNodeViews.tsx
@@ -358,23 +358,23 @@ window.__ModuleLoader__.load({
358
358
  return status === "completed" || status === "failed" || status === "cancelled" || status === "interrupted";
359
359
  }
360
360
  //#endregion
361
- //#region \0dsh-css:C:\Users\QUAN\AppData\Local\Temp\dsh-voco-release-0.2.6\packages\ui-voice\src\client\VoiceOverlay.module.css.mjs
362
- const css = ".JSeWVG_root{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-overlay);max-width:min(520px,100vw - 36px);min-height:36px;box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);pointer-events:auto;border-radius:12px;align-items:center;gap:10px;padding:4px 6px 4px 12px;font-size:12px;line-height:18px;display:flex;position:absolute;bottom:18px;right:18px}.JSeWVG_wave{width:18px;height:18px;color:var(--dsw-alias-state-business-primary);flex:none;justify-content:center;align-items:center;gap:2px;display:inline-flex}.JSeWVG_wave i{background:currentColor;border-radius:1px;width:2px;height:5px;animation:.9s ease-in-out infinite alternate JSeWVG_voice-wave}.JSeWVG_wave i:nth-child(2){height:11px;animation-delay:-300ms}.JSeWVG_wave i:nth-child(3){height:8px;animation-delay:-600ms}.JSeWVG_wave i:nth-child(4){height:4px;animation-delay:-150ms}.JSeWVG_root[data-state=connecting] .JSeWVG_wave,.JSeWVG_root[data-state=error] .JSeWVG_wave{opacity:.55}.JSeWVG_root[data-state=error] .JSeWVG_wave{color:var(--dsw-alias-state-error-primary)}.JSeWVG_status{text-overflow:ellipsis;white-space:nowrap;flex:0 0 4em;min-width:0;overflow:hidden}.JSeWVG_root[data-muted=true] .JSeWVG_wave{color:var(--dsw-alias-state-error-primary);opacity:.65}.JSeWVG_root[data-muted=true] .JSeWVG_status{color:var(--dsw-alias-state-error-primary);font-weight:600}.JSeWVG_root[data-muted=true] .JSeWVG_wave i{animation:none}.JSeWVG_link,.JSeWVG_stop{min-height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:7px;flex:none;padding:0 8px}.JSeWVG_link:hover:not(:disabled),.JSeWVG_stop:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.JSeWVG_link:disabled{cursor:default;opacity:.45}.JSeWVG_stop{color:var(--dsw-alias-state-error-primary)}@keyframes JSeWVG_voice-wave{to{transform:scaleY(.55)}}@media (prefers-reduced-motion:reduce){.JSeWVG_wave i{animation:none}}";
363
- const tagId = "@flowingspring/dsh-voco/VoiceOverlay.module.css";
364
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
361
+ //#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceOverlay.module.css.mjs
362
+ const css$1 = ".GPPB2G_root{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-overlay);max-width:min(520px,100vw - 36px);min-height:36px;box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);pointer-events:auto;border-radius:12px;align-items:center;gap:10px;padding:4px 6px 4px 12px;font-size:12px;line-height:18px;display:flex;position:absolute;bottom:18px;right:18px}.GPPB2G_wave{width:18px;height:18px;color:var(--dsw-alias-state-business-primary);flex:none;justify-content:center;align-items:center;gap:2px;display:inline-flex}.GPPB2G_wave i{background:currentColor;border-radius:1px;width:2px;height:5px;animation:.9s ease-in-out infinite alternate GPPB2G_voice-wave}.GPPB2G_wave i:nth-child(2){height:11px;animation-delay:-300ms}.GPPB2G_wave i:nth-child(3){height:8px;animation-delay:-600ms}.GPPB2G_wave i:nth-child(4){height:4px;animation-delay:-150ms}.GPPB2G_root[data-state=connecting] .GPPB2G_wave,.GPPB2G_root[data-state=error] .GPPB2G_wave{opacity:.55}.GPPB2G_root[data-state=error] .GPPB2G_wave{color:var(--dsw-alias-state-error-primary)}.GPPB2G_status{text-overflow:ellipsis;white-space:nowrap;flex:0 0 4em;min-width:0;overflow:hidden}.GPPB2G_root[data-muted=true] .GPPB2G_wave{color:var(--dsw-alias-state-error-primary);opacity:.65}.GPPB2G_root[data-muted=true] .GPPB2G_status{color:var(--dsw-alias-state-error-primary);font-weight:600}.GPPB2G_root[data-muted=true] .GPPB2G_wave i{animation:none}.GPPB2G_link,.GPPB2G_stop{min-height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:7px;flex:none;padding:0 8px}.GPPB2G_link:hover:not(:disabled),.GPPB2G_stop:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.GPPB2G_link:disabled{cursor:default;opacity:.45}.GPPB2G_stop{color:var(--dsw-alias-state-error-primary)}@keyframes GPPB2G_voice-wave{to{transform:scaleY(.55)}}@media (prefers-reduced-motion:reduce){.GPPB2G_wave i{animation:none}}";
363
+ const tagId$1 = "@flowingspring/dsh-voco/VoiceOverlay.module.css";
364
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
365
365
  const tag = document.createElement("style");
366
366
  tag.dataset.plugin = "@flowingspring/dsh-voco";
367
- tag.dataset.pluginCss = tagId;
368
- tag.textContent = css;
367
+ tag.dataset.pluginCss = tagId$1;
368
+ tag.textContent = css$1;
369
369
  document.head.appendChild(tag);
370
370
  }
371
371
  var VoiceOverlay_module_css_default = {
372
- "link": "JSeWVG_link",
373
- "stop": "JSeWVG_stop",
374
- "voice-wave": "JSeWVG_voice-wave",
375
- "status": "JSeWVG_status",
376
- "wave": "JSeWVG_wave",
377
- "root": "JSeWVG_root"
372
+ "status": "GPPB2G_status",
373
+ "link": "GPPB2G_link",
374
+ "root": "GPPB2G_root",
375
+ "stop": "GPPB2G_stop",
376
+ "voice-wave": "GPPB2G_voice-wave",
377
+ "wave": "GPPB2G_wave"
378
378
  };
379
379
  //#endregion
380
380
  //#region ../ui-voice/src/client/VoiceOverlay.tsx
@@ -432,6 +432,90 @@ window.__ModuleLoader__.load({
432
432
  });
433
433
  }
434
434
  //#endregion
435
+ //#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceSessionMarkers.module.css.mjs
436
+ const css = "._0brRca_slot{flex:none;justify-content:center;align-items:center;width:16px;height:20px;display:inline-flex}._0brRca_marker{width:16px;height:16px;color:var(--dsw-alias-state-business-primary);pointer-events:none;justify-content:center;align-items:center;display:inline-flex}._0brRca_marker svg{width:14px;height:14px;display:block}";
437
+ const tagId = "@flowingspring/dsh-voco/VoiceSessionMarkers.module.css";
438
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
439
+ const tag = document.createElement("style");
440
+ tag.dataset.plugin = "@flowingspring/dsh-voco";
441
+ tag.dataset.pluginCss = tagId;
442
+ tag.textContent = css;
443
+ document.head.appendChild(tag);
444
+ }
445
+ var VoiceSessionMarkers_module_css_default = {
446
+ "slot": "_0brRca_slot",
447
+ "marker": "_0brRca_marker"
448
+ };
449
+ //#endregion
450
+ //#region ../ui-voice/src/client/VoiceSessionMarkers.tsx
451
+ /**
452
+ * The workspace package currently owns the session-row renderer and does not
453
+ * expose a row-level slot. This small, read-only decorator keeps the marker in
454
+ * sync with that renderer while leaving row interactions and layout intact.
455
+ */
456
+ function VoiceSessionMarkers({ useSessions, useVoiceHistory }) {
457
+ const sessions = useSessions((state) => state.byId);
458
+ const history = useVoiceHistory((state) => state.entries);
459
+ (0, react.useEffect)(() => {
460
+ const voiceTitles = new Set(history.map((entry) => entry.sessionId));
461
+ const titles = new Set([...voiceTitles].map((id) => sessions[id]?.displayTitle).filter((title) => title !== void 0));
462
+ let frame = 0;
463
+ const decorate = () => {
464
+ frame = 0;
465
+ const rows = document.querySelectorAll("[role=\"treeitem\"].sessionRow, [role=\"treeitem\"][class*=\"sessionRow\"]");
466
+ for (const row of rows) {
467
+ const title = row.querySelector("[class*=\"title\"]")?.textContent?.trim();
468
+ const slot = row.querySelector("[class*=\"slot\"]");
469
+ const marker = row.querySelector("[data-voice-session-marker]");
470
+ if (!(title !== void 0 && titles.has(title))) {
471
+ marker?.remove();
472
+ continue;
473
+ }
474
+ if (marker !== null) continue;
475
+ (slot ?? createMarkerSlot(row)).append(createMarker());
476
+ }
477
+ };
478
+ const schedule = () => {
479
+ if (frame !== 0) return;
480
+ frame = requestAnimationFrame(decorate);
481
+ };
482
+ decorate();
483
+ const observer = new MutationObserver(schedule);
484
+ observer.observe(document.body, {
485
+ childList: true,
486
+ subtree: true,
487
+ characterData: true
488
+ });
489
+ return () => {
490
+ observer.disconnect();
491
+ if (frame !== 0) cancelAnimationFrame(frame);
492
+ document.querySelectorAll("[data-voice-session-marker]").forEach((node) => {
493
+ node.remove();
494
+ });
495
+ document.querySelectorAll("[data-voice-session-marker-slot]").forEach((node) => {
496
+ node.remove();
497
+ });
498
+ };
499
+ }, [history, sessions]);
500
+ return null;
501
+ }
502
+ function createMarkerSlot(row) {
503
+ const slot = document.createElement("span");
504
+ slot.dataset.voiceSessionMarkerSlot = "";
505
+ slot.className = VoiceSessionMarkers_module_css_default.slot ?? "voice-session-marker-slot";
506
+ const title = row.querySelector("[class*=\"title\"]");
507
+ row.insertBefore(slot, title ?? row.firstChild ?? null);
508
+ return slot;
509
+ }
510
+ function createMarker() {
511
+ const marker = document.createElement("span");
512
+ marker.dataset.voiceSessionMarker = "";
513
+ marker.className = VoiceSessionMarkers_module_css_default.marker ?? "voice-session-marker";
514
+ marker.setAttribute("aria-hidden", "true");
515
+ marker.innerHTML = "<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 8h1.5M6 5v6M9 3.5v9M12 5.5v5M14 7h-1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\" stroke-linecap=\"round\"/></svg>";
516
+ return marker;
517
+ }
518
+ //#endregion
435
519
  //#region ../ui-voice/src/client/voice-controller.ts
436
520
  const INITIAL_SNAPSHOT = {
437
521
  state: "off",
@@ -1465,6 +1549,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
1465
1549
  },
1466
1550
  stopVoice
1467
1551
  });
1552
+ const voiceSessionMarkersInjected = () => ({ hooks: { voiceHistory: history.snapshot } });
1468
1553
  const utteranceInjected = () => ({ hooks: { voice: controller } });
1469
1554
  const delegationInjected = () => ({
1470
1555
  hooks: { voice: controller },
@@ -1514,6 +1599,13 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
1514
1599
  locale: NS,
1515
1600
  inject: voiceOverlayInjected
1516
1601
  }, VoiceOverlay));
1602
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
1603
+ name: "shell.overlay",
1604
+ id: "voice-session-markers",
1605
+ order: 10,
1606
+ locale: NS,
1607
+ inject: voiceSessionMarkersInjected
1608
+ }, VoiceSessionMarkers));
1517
1609
  ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
1518
1610
  name: "sidebar.footer.action",
1519
1611
  id: "voice-history",