🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

语音状态提示音 lijiawei255/dsh-status-chime

DeepSeek Harness
lijiawei25540 天前有提交已提供中文文档扫描:含敏感能力

用声音长短区分任务紧急程度,离开屏幕也能听见

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add lijiawei255/dsh-status-chime
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · ui
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
数据截至 2026/09/26·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]—
更新放缓:最近一次提交在 40 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 16 处,展示前 10 条)
  • 读取本地文件
    lib/index.js:288
    for (const candidate of CONFIG_CANDIDATES) if (existsSync(candidate)) return candidate;
  • 读取本地文件
    lib/index.js:295
    if (!existsSync(path)) return { ...DEFAULTS };
  • 读取本地文件
    lib/index.js:296
    const stamp = statSync(path).mtimeMs;
  • 读取本地文件
    lib/index.js:300
    const raw = JSON.parse(readFileSync(path, 'utf8'));
  • 读取本地文件
    lib/index.js:321
    if (existsSync(path)) current = JSON.parse(readFileSync(path, 'utf8'));
  • 读取本地文件
    lib/index.js:321
    if (existsSync(path)) current = JSON.parse(readFileSync(path, 'utf8'));
  • 写入本地文件
    lib/index.js:326
    mkdirSync(dirname(path), { recursive: true });
  • 写入本地文件
    lib/index.js:327
    writeFileSync(path, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
  • 执行外部命令来自配置/变量
    lib/index.js:399
    const probe = spawnSync(exe, ['-version'], { windowsHide: true, timeout: 5000, stdio: 'ignore' });
  • 执行外部命令来自配置/变量
    lib/index.js:444
    const child = spawn(exe, argv, { stdio: 'ignore', windowsHide: true, env: env ?? process.env });
扫描于 2026/11/4(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 声音长短区分紧急度
  • 八种场景提示音
  • 零第三方依赖

DeepSeek Harness 的语音状态提示,用片段时长编码紧急度:2 秒的审批提示音对比 8 秒的失败播报。八个场景,在 Windows 10/11 上零第三方依赖。· DSH 语音状态提示:用时长编码紧急度,零第三方依赖。

README

由 DeepSeek 最新模型翻译生成
dsh-status-chime | English 给 DeepSeek Harness 加上「会说话的状态提示」:任务跑完、出错、后台任务结束、需要你回答时,用声音告诉你,而不是只让任务栏图标闪一下。 platform license Awesome DSH Plugin 为什么做这个 DSH 自带的通知是视觉的:任务栏图标闪烁 + 系统气泡。这类提示有一个隐含前提——你得正在看着屏幕。 但真正需要被通知的时刻,往往正是你不在屏幕前的时候: - 一个跑了十几分钟的任务终于结束 - 后台任务失败,而你已经切去干别的了 - 代理停下来等你回答一个问题,却在原地等了半小时 - 目标被卡住,需要你介入才能继续 于是提示被错过,时间被浪费。换成声音之后,「必须盯着」就变成了「听得见就行」——你可以去泡杯茶、看会儿书、或者在另一台机器上干活。 装好即用,不需要配置任何东西。 八个场景 时长是刻意设计的:长 = 有事需要你,短 = 有事情结束了。
展开完整文档(README 剩余 1 节)
dsh-status-chime

| English

给 DeepSeek Harness 加上「会说话的状态提示」:任务跑完、出错、后台任务结束、需要你回答时,用声音告诉你,而不是只让任务栏图标闪一下。

platform
license
Awesome DSH Plugin

为什么做这个

DSH 自带的通知是视觉的:任务栏图标闪烁 + 系统气泡。这类提示有一个隐含前提——你得正在看着屏幕。

但真正需要被通知的时刻,往往正是你不在屏幕前的时候:

- 一个跑了十几分钟的任务终于结束
- 后台任务失败,而你已经切去干别的了
- 代理停下来等你回答一个问题,却在原地等了半小时
- 目标被卡住,需要你介入才能继续

于是提示被错过,时间被浪费。换成声音之后,「必须盯着」就变成了「听得见就行」——你可以去泡杯茶、看会儿书、或者在另一台机器上干活。

装好即用,不需要配置任何东西。

八个场景

时长是刻意设计的:长 = 有事需要你,短 = 有事情结束了。

准确地说,它是三个带,而不是「每一条都比下一条长一截」:

| 带 | 时长范围 | 场景 |
| 失败 / 受阻 —— 最需要你 | 4.8 – 8.0s | turn-error、job-failed、goal-blocked |
| 在等你动手 | 3.0s | approval |
| 事情结束(或只是简单问一句) | 1.6 – 2.6s | job-done、goal-complete、needs-input、turn-done |

同一带内的两条刻意靠得很近,因为它们的紧急度本来就同级:goal-complete(2.16s)和 needs-input(2.09s)只差 0.072s,中文那套也一样(差 0.072s)。靠声音长短能分辨的是「带」,不是每一条。

| 场景 | 什么时候响 | 中文 | 英文 | 紧急度 |
| turn-error | 本轮失败,或撞到 token 上限 | 7.97s | 7.90s | 失败/受阻 —— 最长 |
| job-failed | 后台任务失败 | 5.95s | 6.46s | 失败/受阻 |
| goal-blocked | 目标受阻,需要你介入 | 4.78s | 4.85s | 失败/受阻 |
| approval | 有操作在等你批准 | 3.00s | 3.00s | 在等你动手 |
| job-done | 后台任务完成 | 2.59s | 2.59s | 已结束 |
| goal-complete | 目标整体完成(只响一次,不是每轮) | 2.16s | 2.16s | 已结束 |
| needs-input | 代理停下来等你回答 | 2.09s | 2.09s | 简单问一句 |
| turn-done | 你发起的那一轮正常结束 | 1.58s | 1.92s | 已结束 —— 最短 |

⚠️ 两套时长不一样,别混用。 中文和英文是各自合成的(不同音色、不同语言),所以顺序一致但数值不同:英文 job-failed 是 6.46s,中文是 5.95s。上表两列都给了,按你实际用的语言看那一列。

两条过滤规则值得单独说明,它们避免了这个插件变成噪音源:

- turn-error 不看是否由你发起。自动续跑的回合出错,同样需要你知道。
- turn-done 只看你发起的回合。否则一个跑 20 轮的目标会响 20 次「任务完成」。自动推进的进度由 goal-complete / goal-blocked 在目标级别汇报,而不是每一轮。

approval 只在审批策略为 ask(需要人工确认)时才会响 —— 策略是 never 时没有任何东西在等你,自然也不该出声。它监听的是会话事件 approval/asked,这条在 ask 策略下必定派发;另外还挂了作用域瀑布 approval/request 作兜底,两条路径播的是同一条音。

音频试听(GitHub 的 Markdown 不支持内嵌播放器,所以放在 Release 里,点开即可播放):见 v0.4.0 release 的 16 个音频附件——不带后缀的是中文(默认那套),带 .en 的是英文。

链接钉在具体 tag 上而不是 latest,并且每个 release 都重新附上这 16 个文件:音频自 0.3.0 起一个字节都没变(0.4.0 只改了代码),所以每个版本页都能直接试听,不必依赖"某个旧版本还留着附件"。

⚠️ 那些附件只是试听用的,不是安装产物:安装走 dsh plugin add,插件包里本来就带了全部 32 个文件(16 条 × mp3 + wav),不需要从 Release 下载任何东西。

两种语言:中文(默认)和英文

同一套安装包,八条场景各带中英两版音频,来回切换不需要重装。默认是中文。

/voice-alerts lang # 看当前语言 /voice-alerts lang en # 切到英文 /voice-alerts lang zh # 切回中文

切换会写回配置文件(language 字段),重启后仍然生效。也可以直接改配置:

{ "language": "en" }

英文不是翻译,是重写的

这一点值得说明,因为它关系到这个插件的核心设计。

中文原文直译成英文会变长、变平,而「时长 = 紧急度」正是这个插件唯一的信息载体 —— 一旦英文长度失控,光凭声音长短判断要不要过去就失效了。所以英文八条是按英语语境重写的,不是逐句翻译:

| 场景 | 中文 | 英文 |
| turn-done | 任务完成。 | 回合完成。 |
| needs-input | 需要你回答。 | 等待你的回答。 |
| goal-complete | 目标已完成。 | 目标已完成。 |
| job-done | 后台任务完成。 | 后台任务已完成。 |
| approval | 有操作等待你批准。 | 有操作等待你的批准。 |
| goal-blocked | 目标受阻,需要你介入处理后才能继续。 | 目标受阻。需要你介入后才能继续。 |
| job-failed | 后台任务失败,请回到 DSH 查看详情。 | 后台任务失败,需要你处理。查看 DSH 了解详情。 |
| turn-error | 任务执行出错,本轮未能完成,请回到 DSH 查看错误详情。 | 回合失败,因此本轮未完成。打开 DSH 查看错误详情,然后重试。 |

英文版的时长梯度是 1.92s → 7.90s,与中文同样单调(同样按严重度递增)。真正拉开的是三个紧急度带:跨进「失败/受阻」带的那一步有 38%(3.00s → 4.85s)。同一带内刻意靠得近 —— goal-complete(2.16s)与 needs-input(2.09s)只差 0.072s,中文那套也一样。所以靠长短分辨的是带,不是每一条。

⚠️ 这里踩过一个坑,记下来:英文 turn-error 最初只有 16 个词、6.55s,而 job-failed 是 6.46s —— 只差 0.09s,耳朵根本分不出来。中文那边两者差 2.02s(25%,相对较长者;本文件所有百分比都按这个口径)。后来把英文错误文案加长到 19 个词,才恢复到 7.90s / 1.44s 的差距。如果你改文案,记得重新量一遍时长,别只看中文字数。

英文用的音色是 loongmary(温暖英音),不是让中文音色去读英文。试听过三个候选并做了排序(scripts/qa.mjs rank,产物写到 qa/,该目录不进版本控制;重跑一次名次不变)。中文音色读英文得分最低,评语是「明显合成感、节奏不自然」——自然度 4/10、音色 5/10(这两个分数容易记混,naturalness 是 4,character 才是 5)。

/voice-alerts status 会同时列出两种语言各自的音频是否齐备:

Clip sets: zh (active): all clips present | en: all clips present

装之前先知道三件事

1. 平台:Windows 10/11。 保底播放器用的是 Windows 自带的 PowerShell + System.Media.SoundPlayer,没有 macOS / Linux 支持。装了 ffmpeg 会优先用 ffplay,但那只是可选增强。
2. 需要 DSH Desktop,以及能跑 dsh 命令的终端。装插件走 dsh plugin,它内部调用 pnpm(见下面的坑)。
3. 音频不用装任何东西 —— 中英两套 32 个音频文件都在包里。

⚠️ 一次性提醒:包名和运行时名字不一样

这个容易让人找错地方,先说清楚:

| | 名字 |
| npm 包 / GitHub 仓库 | dsh-status-chime |
| 斜杠命令 | /voice-alerts |
| 日志前缀 | [voice-alerts] |
| 配置文件 | $DSH_HOME/voice-alerts.config.json(主路径) |
| 音频目录 | $DSH_HOME/voice-alerts/clips/ |
| cordis id | voice-alerts |

配置还有一个兼容用的旧位置 $DSH_HOME/voice-alerts/voice-alerts.config.json。插件只读先找到的那一个(先查主路径),所以:如果主路径的文件已存在,你改旧位置那个文件会被静默忽略。

写入是写回它实际读到的那一个文件:主路径存在就写主路径,否则写旧位置;两个都不存在时才新建主路径。所以在"只有旧位置文件"的安装上,/voice-alerts lang 和 on/off 更新的是旧位置那个文件,不是主路径。拿不准时看启动日志里的 config 那一行——它写的就是真正在用的文件。

包名在 0.3.0 从 dsh-voice-alerts 改成了 dsh-status-chime(原来的名字和社区目录里另一个插件只差一个字母,会被市场规则隐藏)。改名只动包名和仓库名:命令、配置路径、日志前缀全都还是 voice-alerts,所以老用户升级不会坏。

排查问题时去日志里 grep voice-alerts,不是 dsh-status-chime。

安装

方式一:交给你的 Agent(推荐)

把下面这句话发给你的 DSH:

把 https://github.com/lijiawei255/dsh-status-chime 装进我的 DSH desktop profile,装完提醒我重启。

仓库里有一份 INSTALL.md,写清了每一步该做什么。它存在的意义是:让不同的 Agent 装出同样的结果,而不是各自发挥。

方式二:自己敲命令

把 换成你自己的 profile 名(通常是 desktop)。先看一眼 $DSH_HOME/profiles/ 下有哪些目录再决定,不要照抄别人的:

从 GitHub 直接装
dsh plugin --profile add github:lijiawei255/dsh-status-chime

或者先 clone / 下载 ZIP,再指向本地目录powershell
git clone https://github.com/lijiawei255/dsh-status-chime
dsh plugin --profile add .\dsh-status-chime

这条命令会做两件事:把包装进 profile,并把包登记为一个 profile 层(前提是包里声明了 dsh.bundle,本仓库已经声明了)。

⚠️ 如果报 ERR_PNPM_ADDING_TO_ROOT:profile 自带一个声明了 packages: [.] 的 pnpm-workspace.yaml,pnpm 9 会因此拒绝裸 add。加一个 -w 即可: powershell
dsh plugin --profile add -w github:lijiawei255/dsh-status-chime

(实测过的是:pnpm 9 会报错、pnpm 11.8.0 正常;pnpm 10 没测过。所以最稳的是加 -w。)详见 TROUBLESHOOTING.md 第 11 条。

装完必须完全重启 DSH Desktop,否则插件不会加载。

重启之后

在聊天框里敲:

/voice-alerts status

看到 Voice alerts: on (v0.4.0)、Language: zh、Scenes (8) 就说明装好了。想听一遍全部八条:

/voice-alerts

卸载 powershell
dsh plugin --profile remove dsh-status-chime

卸载不会删除你 $DSH_HOME 下的东西。想彻底清干净,删这两处: powershell 音频、play.ps1、clips.json Remove-Item -Recurse -Force "$env:USERPROFILE\.dsh\voice-alerts" 运行时配置(配置不在上面那个目录里,是同级的一个文件) Remove-Item -Force "$env:USERPROFILE\.dsh\voice-alerts.config.json"

卸载后需要完全重启 DSH Desktop 才生效。

⚠️ 质检报告不在 $DSH_HOME 下,也不随包发布:qa/report.md 由开发脚本 scripts/qa.mjs 写进仓库检出目录里的 qa/。那个目录在 .gitignore 里、也不在 package.json 的 files 中,所以用 dsh plugin add 装出来的用户没有这个文件(要跑质检得先克隆仓库)。

它怎么工作

DSH 事件 ──▶ lib/index.js ──▶ 聚合 / 节流 / 优先级 ──▶ 播放器 ──▶ 音频文件

事件来源(都是宿主进程里的公开事件):

| 事件 | 用途 |
| session/event → turn/start / user/message / turn/end | 判断这一轮是不是你发起的,以及它是怎么结束的 |
| session/event → goal/change | 目标的 complete 与 block |
| jobs.events.subscribe → settled | 后台任务结束;completed 播、failed 播、killed 不播,awaited(已有等待者收走结果)与 cause: 'teardown'(退出/归档)也都不播 |
| tools/pre-execute | 工具名命中 waitingTools 时,说明代理要停下来等你 |
| session/event → approval/asked | 主路径:审批策略为 ask 时必定派发 |
| approval/request | 兜底:作用域瀑布,同样只在 ask 下可能派发;两条路播同一条音 |

播放规则:同一 400 毫秒窗口内的多个事件只播优先级最高的那条;同一场景 1.5 秒内不重复;新的提示会打断正在播的那条。

运行时零网络:插件只读本地音频文件、只启动本地播放器。不联网、不上传、不校验。

技术栈:用大模型给声音做「预审」

这部分是我觉得最值得分享的地方。

给提示音挑一个合适的音色,传统做法是一个个盲听:试 10 个音色、改 20 次风格描述、听到耳朵疲劳,最后凭模糊印象拍板。这个项目换了个做法——让大模型先做初筛和排序,人只在筛出来的少数里做最终决定。

具体是三件事:

1. 用全模态模型当评审(核心)

tools/qw_local_omni.py 把多段候选音频一次性交给 Qwen-Omni,让它横向比较并按维度打分: powershell
python tools/qw_local_omni.py preview/flash-mary-en.mp3 preview/flash-eva-en.mp3 preview/flash-yuanfei-en.mp3
--message "横向比较这几段录音,按清晰度/自然度/音色/干净度打分并排序"

拿到的是一个排序而不是一堆孤立分数——「A 比 B 更贴目标」这种相对判断,比「A 得 7 分」有用得多。实测给出的排序和理由相当具体(下面是模型理由的概述):

A4 在保持系统提示所需的清晰稳重之外,音色最贴合目标;A2 辨识度不足,A5 偏平淡,A1、A3、A6 则因音色过亮或偏年轻而被排除。

2. 用 ASR 转写回读做客观校验

光听着顺耳不够——TTS 可能吞字、念错、把缩写拆开读。tools/qw_local_asr.py 把音频转回文字,与预期文案做字符级相似度比对: powershell
python tools/qw_local_asr.py assets/clips/turn-error.mp3 --lang zh

这条是可以当硬门槛的客观指标:文案是已知的,转写对不对是机械可判的。本项目中英各 8 条、共 16 条音频的相似度都是 1.000。

3. 时长梯度作为信息编码

上面表格里的时长不是随手定的,而是把「严重程度」编码进了音频自身:长 = 需要你出手。这样即使手机在旁边、屏幕没看,也能靠声音长短判断该不该放下手里的事。
由此得到的完整流程(scripts/ 里两个脚本,可直接复现):

scripts/build.mjs audition 出多个音色候选 ↓ scripts/qa.mjs rank 全模态模型横向排序(不做 ASR;回读在下一步) ↓ 人听筛出来的前 2-3 个,拍板 ← 决策量被压缩到很少 ↓ scripts/build.mjs build 批量生成 + 响度归一 ↓ scripts/qa.mjs clips 全部质检过关

一点经验:不要把大模型的主观打分当硬门槛。实测同一段音频两次评分能从「自然 6 / 音色 4」跳到「自然 9 / 音色 7」,四段明显不同的音频甚至拿到过完全一样的分数。所以本项目把指标分了两层——客观项(ASR 相似度、有无削波、清晰度、干净度)当门槛,主观项(自然度、音色、成熟度)只作参考,最终由耳朵决定。这个分工是这套流程能稳定跑起来的关键。

后来补上的三条检查,都是先发现了具体漏洞才加的:

| 检查 | 性质 | 为什么加 |
| 静音下限(峰值 ≥ −30 dB、均值 ≥ −35 dB) | 硬门槛 | 原来的峰值检查只抓削波,所以「时长正常但内容全静音」这种经典 TTS 失效能全项通过。实测成品峰值 −4.2…−1.9 dB、均值 −20.6…−16.6 dB,而全静音是 −91 dB。两条线的余量不一样:峰值门槛离最差成品 25.8 dB(−4.2 vs −30),均值门槛 14.4 dB(−20.6 vs −35) |
| 净语速(去掉停顿后的单位/秒) | 参考项 | 中文刻意放慢(rate 0.95),套用人类播报那个 3.2–5.5 字/秒会把八条里的七条判失败。对这个项目真正有意义的是条与条之间的一致性(因为时长承载紧急度),所以跟同语言中位数比;少于 5 个单位的短句豁免,否则两个词的 clip 会假报警 |
| UTMOS(MOS 预测器) | 参考项 | 给自然度一个可复现的数字,补上「大模型打分不稳定」那一环。必须按语言分别比:它给英文八条的分全部高于中文八条(4.38–4.51 vs 3.75–4.28),跨语言比会读成中文那套有缺陷 |

这三条都有反向验证(scripts/qa-negative-control.mjs,离线运行、不花 API 额度):注入全静音、极安静、语速拉长三类缺陷,断言门槛确实报出来,同时确认健康音频不会被误伤。一个只会说「通过」的检查器没有价值。

顺带记一个坑:加静音下限之前,先用 ttsproof(一个现成的 TTS QA 工具)试过。它能抓削波和截断,但抓不到全静音 —— 它源码里的 empty_audio 只判断「文件不存在或 ≤44 字节」,不看音频内容。所以那条下限是自己加的,不是从工具里白拿的。

配置

配置文件:$DSH_HOME/voice-alerts.config.json($DSH_HOME 通常是 ~/.dsh)。
找不到这个文件时使用内置默认值,所以不配置也能正常用。文件按修改时间热读取,改完立即生效,不需要重启。

完整模板见 assets/voice-alerts.config.json。常用项:

| 配置项 | 默认 | 说明 |
| enabled | true | 总开关 |
| volume | 85 | 0-100,只对 ffplay 生效 |
| minIntervalMs | 1500 | 同一场景的重复触发抑制窗口 |
| coalesceMs | 400 | 事件聚合窗口,窗口内只播最高优先级那条 |
| interrupt | true | 新提示是否打断正在播的 |
| scenes..enabled | true | 单独关掉某个场景 |
| player | "auto" | auto / ffplay / powershell |
| ffplayPath | null | 显式指定 ffplay 路径(不在 PATH 上时用) |
| playPs1Path | null | 显式指定回退脚本 play.ps1 的路径 |
| commandName | "voice-alerts" | 斜杠命令名。与别的插件重名时只丢命令,不影响出声 |
| waitingTools | ["ask_user_question","exit_plan_mode"] | 命中即视为「在等你回答」;DSH 若改工具名可在此覆盖 |
| language | "zh" | 语音语言:zh / en;无法识别的值回退到 zh(不会静默) |
| watchApprovals | true | 审批请求是否出声(只在策略为 ask 时可能触发) |
| clipsDir | null | 自定义音频目录,优先级最高 |

命令

| 命令 | 作用 |
| /voice-alerts | 依次播放全部八条(当前语言) |
| /voice-alerts on / off | 立即开关(会写回配置文件) |
| /voice-alerts lang | 切换语音语言,写回配置 |
| /voice-alerts status | 看播放器探测结果、各语言各场景音频是否齐备 |
| /voice-alerts test | 只播一条,用来排查某类事件有没有触发 |

换成你自己的声音

音频不是必须用仓库里这 8 条(中英各 8 条)。完整流程: powershell
1. 改 assets/clips.json:文案在 clips..text,音色在 model/voice/instruction
2. 换音色时先出样试听(把候选写在 voiceCandidates 里)
node scripts/build.mjs audition
node scripts/qa.mjs rank # 大模型帮你排序,人只挑最终那条
3. 把选定的 model/voice/instruction 写回 clips.json,然后批量生成
node scripts/build.mjs build
node scripts/qa.mjs clips # 质检
生成音频需要:ffmpeg(响度归一与转码)、Python 3(质检脚本)、阿里云百炼 CLI(TTS/ASR/Omni)。这三样只有你想自己生成时才需要——用仓库自带音频的话,什么都不用装。

生成后会有 mp3 与 wav 两份。不要删掉 wav:PowerShell 回退播放器只认未压缩 PCM,它是「干净 Windows 上零依赖」的保证。

自己生成的音频放在 $DSH_HOME/voice-alerts/clips/ 会自动优先于包内的(逐文件覆盖,所以只想换一条也可以)。

文件名规则要记住(想只替换一条英文音频时必须知道):

| 语言 | 文件名 |
| 中文(默认) | .mp3 / .wav,例如 turn-done.mp3 |
| 英文 | .en.mp3 / .en.wav,例如 turn-done.en.mp3 |

默认语言用不带后缀的名字,其它语言加 . 中缀。 所以只想换英文的 approval,就放一个 approval.en.mp3(以及 .wav,如果你用 PowerShell 回退播放器)。

装了没声音?

按这个顺序排查,能覆盖绝大多数情况。完整版见 TROUBLESHOOTING.md。

1. 重启了吗? 插件文件不热加载,改完或装完必须完全重启 DSH Desktop。
2. /voice-alerts status 看 Player 那一行。unavailable 说明两条播放路径都没探测到。
3. Windows 音量合成器把 ffplay(或 powershell.exe)单独静音了——这是最常见的原因。右键任务栏音量图标 → 打开音量合成器,检查对应条目。
4. 输出设备选错了。
5. 某个场景被关掉了,或 enabled 是 false。
6. 日志里有 no audio for (例如 no zh audio for turn-done)→ 该语言的音频文件缺失。
7. 日志里有 throttled → 被节流窗口挡住了,属于正常行为。
8. 命令打了没反应? 如果 /voice-alerts 单独打能播(试听 + 状态),但带上参数(lang en、on、test )就毫无反应、反而像发了一条普通消息,多半是中文输入法把 / 打成了全角 /,或者命令名里混进了大写(必须是全小写 voice-alerts)。这两种都会让整行不被认作命令。从自动补全列表里选中命令可以同时避开这两点。详见 TROUBLESHOOTING.md 第 14 节。

日志位置:%APPDATA%\DSH Desktop\logs\host\dsh-.log,搜 voice-alerts。

⚠️ 一件事先说明:日志里没有 ffplay 不是故障。ffplay 属于 ffmpeg,需要另外安装;它只是让启动快一点、音量可独立调节。没有它时插件会用 Windows 自带的 PowerShell 播放器,功能完全正常。

平台与依赖

支持:Windows 10 / 11。

干净 Windows 上不需要安装任何第三方依赖就能出声,因为保底播放器用的是系统自带的 Windows PowerShell 5.1 + .NET System.Media.SoundPlayer。

| 情况 | 需要什么 |
| 干净 Windows 10/11,只装了 DSH | 什么都不用装,用系统自带播放器,启动开销约 0.4 秒 |
| 装了 ffmpeg | 无需配置,自动改用 ffplay:启动更快、volume 配置生效 |
| 想自己生成音频 | 额外需要 ffmpeg + Python 3 + 阿里云百炼 CLI |
| 运行时网络 | 零网络 |

播放后端的选择顺序:

1. ffplay(如果探测到)—— 直接播 mp3,支持独立音量
2. Windows PowerShell + SoundPlayer —— 系统自带,只认 wav,音量跟随系统先试 -File play.ps1(可审计的磁盘脚本);若被执行策略或 ACL 拦住,自动改用 -EncodedCommand 内联命令重试一次
3. 两条都不通 → 静默降级,只在日志里记一行

宿主侧拿不到窗口是否聚焦(DSH 的 native 桥只暴露了 notifyAttention 等接口),所以这个插件任何时候都会出声,包括你正看着窗口的时候。如果觉得吵,用 /voice-alerts off 或调 volume。

验证状态

我一向觉得,把「写过」和「验证过」分开讲清楚,比含糊地说「功能完整」有用得多。所以逐条列出,并且明确写出验证的边界。

下面这张表是摘要。逐条的原始证据、测量值、以及「没验证到哪一步」都记在 docs/verification.md —— 想核对任何一个数字就去看那份。

验证边界(请先读这一段)

以下结论全部来自同一台机器上的验证:

| 项 | 值 |
| 操作系统 | Windows 11 |
| DSH | DSH Desktop(官方版),@deepseek-ai/dsh 0.1.7-rc.2 |
| 该机器上的额外软件 | 装有 ffmpeg、Python 3、阿里云百炼 CLI |

上一版(0.3.0)验证的是 0.1.5-rc.2。0.1.7 移除了 jobs.onJobDone,后台任务两个场景因此静默失效;0.4.0 就是为这件事发的——它改用 0.1.7 的 jobs.events.subscribe,同时保留对旧 API 的回退,所以 0.1.5/0.1.6 也照常可用。

这意味着:

- ✅ 代码正确性、事件映射、音频质量——与本机装了什么无关,结论可迁移到你的机器。
- ✅ 「干净 Windows 零依赖」——保底播放器用的是 Windows 自带的 PowerShell 5.1 + .NET System.Media.SoundPlayer,两者都是 Win10/11 的操作系统组件;无 ffmpeg 的情形已通过模拟验证。
- ⚠️ DSH 版本——在 0.1.7-rc.2 与 0.1.5 系上验证过(后者由自测的旧 API 阶段模拟,不是真机)。再往后的版本若又改事件接口,某些场景可能再次失效。这是唯一真正未知、且我无法在本机消除的变数。
- ⚠️ 在一台完全干净的、别人的 Windows 上从 GitHub 安装——我没有第二台机器,没有实测过这一步。CI(见下)在 GitHub 提供的干净 Windows 运行器上覆盖了「安装 + 加载 + 后端探测」,但运行器没有声卡,无法验证声音真的到了扬声器。

如果你在别的 DSH 版本或别的机器上遇到问题,请提 Issue 并附上日志里的 [voice-alerts] active … 那一行(它会写明探测到的播放器和配置路径),那基本能一眼定位。

逐层状态

| 层级 | 状态 |
| 事件层 | 8 个场景中 7 个由真实事件触发验证过:turn-done、turn-error、needs-input、job-done、goal-complete、goal-blocked、approval |
| 音频层 | 中英各 8 条、共 16 条全部通过自动质检(ASR 相似度 1.000、清晰/干净 10/10、无削波)。其中中文那 8 条另做过逐条耳听确认;英文那 8 条没做过这一步,只过了自动质检 |
| 后端层 | 强制 PowerShell 会正确选 .wav;模拟「没装 ffmpeg」时自动回退且仍能播;显式指定不存在的 ffplay 会明确失败而不偷偷换后端 |
| 代码层 | scripts/selftest.mjs 用模拟上下文驱动插件,76 项检查覆盖事件映射、过滤规则、优先级、节流、命令、重名冲突、资产解析顺序、语言切换与回退,以及新旧两代 jobs 事件 API 的探测与回退 |
| 语言层 | 默认中文、lang en 切换后确实改选英文文件(自测断言的是解析到的文件名,不只是状态文字);配置里写无法识别的语言会回退到中文而不是静默 |
| CI | .github/workflows/verify.yml 在干净的 windows-latest 上验证:真实安装并登记为 profile 层、清单无 BOM、只依赖 Node 内置模块、32 个音频齐备(8 场景 × 2 语言 × 2 格式)、无 ffplay 时 PowerShell 后端仍被探测到、76 项自检、隐私扫描 |

关于 approval 的验证要说清楚边界:触发时审批策略必须是 ask。我本人是在 ask 策略下听到提示音的,但当时无法区分它走的是会话事件 approval/asked 还是兜底的作用域瀑布 approval/request —— 两条路径播同一条音。会话事件那条的行为由自检覆盖(含「子代理会话的审批不出声」),但它是否在生产环境中被派发,我没有单独取证过。

CI 的详细「证明了什么 / 没证明什么」写在 workflow 文件头部——包括它不能证明声音到达扬声器这一点。

一个已知缺陷,必须说清楚

job-failed 对「后台 shell 命令非零退出」实际不可达。

实测:一个以后台方式运行、exit 7 结束的命令,DSH 把它的状态记为 completed,于是播的是「后台任务完成」。原因是 job 的状态只有 completed / killed / failed 三种终态,而 shell 后台任务的生产者只会产出前两种;failed 保留给「后台工具任务报告错误」或生产方合约违约的情况。这是框架行为,0.1.7 里依然如此,不是本插件的实现问题。

0.1.7 新增了一个可观察点:job 详情里现在带 exit code: N,所以非零退出在日志里看得到了。但我故意不去解析它——那是写给人看的字符串,把它当契约,下次框架改措辞就会静默失效。想要「非零退出也响」的话,正确做法是让 DSH 把退出码变成状态字段,而不是在这里猜文本。

这个场景保留了(它对工具任务失败是有效的),但它的触发未被真实复现过,只有代码层面的核对。你可以用 /voice-alerts test job-failed 验证音频本身没问题。

0.4.0 修的是哪一处

0.1.7 删掉了 jobs.onJobDone,而 0.3.0 只认它——所以升级到 0.1.7 之后,job-done 与 job-failed 两个场景是静默失效的,日志里连一行报错都不会有(异常被宿主按 fiber 吞掉了)。0.4.0 改成订阅 0.1.7 的 jobs.events.subscribe({ owners: 'all' }) 提交流:

- 只认 settled;registered / progress / stopping / output / removed 一律忽略。
- awaited: true(已有等待者收走结果)与 cause: 'teardown'(会话归档、宿主退出)都不出声——否则每次关程序都会响一声,job_wait 也会重复播报。
- 旧 API 仍然保留为回退分支:宿主没有 events.subscribe 时自动走 onJobDone,并在日志里说明用的是哪一条。两条分支都由自测覆盖。

本地与开源:镜像,以及唯一允许的差异

这个项目同时是两样东西:别人下载安装的仓库,和我本机正在跑的那份。两者一旦不一致,麻烦在于它不留痕迹——版本号还是同一个,代码已经变了,于是"我本地测过的"和"你下载到的"就不是一个东西。所以镜像被当成一条可执行的规则,而不是一个承诺。

逐字节镜像(node scripts/sync-profile.mjs --all --check / --apply):

| 本地 | 仓库 |
| 单文件安装的 /.js | lib/index.js |
| $DSH_HOME/voice-alerts/clips/ | assets/clips/(32 个音频) |
| $DSH_HOME/voice-alerts/play.ps1 | assets/play.ps1 |

这条规则不是摆设:这次就靠哈希抓出本地那份落后三笔提交、还差一次宿主 API 迁移,而两边版本号一模一样。
唯一允许的差异是措辞。 $DSH_HOME/voice-alerts/clips.json 是私密母本(措辞按我的原话写,不外发),仓库里的 assets/clips.json 是同一批音频的中性描述——音频不重新生成,32 个文件就是当初试听选中的那批。差异只允许落在:注释、试听候选清单(id / label / instruction)、chosenCandidate 名字、风格 instruction。

而且是机器可验的:sync-profile.mjs 会把每一个差异字段路径分类,功能性差异必须为 0(模型、音色、rate、pitch、volume、format、sampleRate、loudnorm、以及每一句中英文案),非 0 直接以 exit 3 报出来,因为那种差异不是"措辞",改不了也糊不过去。分类方向是保守的:没被归类的字段一律算功能性,所以新增字段不可能被当成"大概只是措辞"混过去。

禁用词表只存在本地:$DSH_HOME/voice-alerts.scan.json(在任何 clone 之外),由 node scripts/scan-sensitive.mjs . 执行。扫描器只报文件、行号、类别,绝不回显命中的内容,所以它的输出可以安全贴进 Issue、CI 日志或对话——检查本身不会变成被检查内容的第二份拷贝。

两点如实说明:

- CI 跑不了这道措辞闸门——GitHub 运行器没有我的 $DSH_HOME,所以 CI 只应用内置规则(凭据、密钥形态、个人路径)。措辞规则保护的是我提交前的那一步。
- 正向对照:扫私密目录(node scripts/scan-sensitive.mjs "$DSH_HOME/voice-alerts")必须报命中;如果它变干净了,说明本地规则没加载,闸门实际上开着。

完整规则、逐项差异与"什么不算措辞差异"(maturity 是 qa.mjs 的评分维度名,保留)见 docs/mirror-policy.md。

目录结构

dsh-status-chime/
├── lib/index.js # 插件主体,唯一运行时代码 ├── cordis.patch.yml # 声明这个包是 profile 层(dsh.bundle 指向它) ├── package.json # 包名、dsh.bundle 声明、engines ├── assets/ │ ├── clips/ # 8 场景 × 2 语言 = 16 条音频,每条 mp3 + wav(共 32 个文件) │ ├── clips.json # 文案/音色/参数的唯一事实源 │ ├── voice-alerts.config.json # 配置模板 │ └── play.ps1 # PowerShell 回退播放器(纯 ASCII,原因见文件头) ├── tools/ # 百炼本地音频辅助脚本(ASR / Omni / UTMOS) ├── scripts/ # 生成 / 质检 / 自检 / 负向验证 / 隐私扫描 │ ├── build.mjs # 生成音频(支持 --lang) │ ├── qa.mjs # 质检(支持 --lang) │ ├── selftest.mjs # 离线自测,76 项 │ ├── qa-negative-control.mjs # 证明质检门槛真的会拦下坏音频 │ ├── verify-local-install.mjs # 验证已安装的单文件版本 │ ├── sync-profile.mjs # 让单文件本地安装与仓库保持一致(--check / --apply) │ ├── scan-sensitive.mjs # 隐私/措辞扫描 │ └── scan-sensitive.verify.mjs # 证明扫描器真的抓得到 ├── docs/verification.md # 逐条验证记录 ├── docs/mirror-policy.md # 镜像规则:什么逐字节相同、什么只允许差措辞 ├── .github/workflows/verify.yml # CI:干净 Windows 上跑安装 + 自测 + 扫描 ├── INSTALL.md # 给 Agent 看的安装步骤 ├── TROUBLESHOOTING.md # 没声音时的排查清单 ├── README.en.md # 英文说明 ├── CHANGELOG.md └── LICENSE # MIT

qa/、preview/、tmp/ 是脚本跑出来的中间产物,已在 .gitignore 里,不随仓库发布。

收录

已被 Awesome DSH Plugin 收录,分类 notify:条目见通知与集成,提交记录 #5553(已合并)。

那个列表是人工 + CI 审核制,不是爬虫采集:要求仓库声明 dsh.bundle、含真实可运行的代码、仓库创建满 1 天,而且条目描述必须和代码对得上。

许可

代码与随包音频均以 MIT 发布。

随包音频是用阿里云百炼(Model Studio)的语音合成生成的,不是任何人的真人录音;如果你打算使用它们,请自行确认你的用法符合相应服务条款。仓库不授予任何底层声音模型的权利。你完全可以不用这套音频——scripts/build.mjs 可以生成你自己的,插件也会优先使用你放在 $DSH_HOME/voice-alerts/clips/ 的文件。

贡献

提交前请跑这两个脚本。第一个确认没有把个人路径或凭据带进来,第二个确认自检仍然全绿: powershell
node scripts/scan-sensitive.mjs .
node scripts/selftest.mjs

scan-sensitive.mjs 只报告文件、行号与命中类别,绝不打印命中内容——所以你在 Issue 里贴它的输出是安全的。它自带的规则集可以用 $DSH_HOME/voice-alerts.scan.json(不提交)追加你自己机器上的私有字符串。想确认它真的能抓到东西,跑 node scripts/scan-sensitive.verify.mjs:它植入几段明显是伪造的凭据形态值并断言扫描器能报出来,同时断言报告不回显这些值。

欢迎提 Issue 与 PR。特别欢迎的:macOS / Linux 的播放后端(当前后端层是 Windows 专用的)。
预览分享卡片长什么样 ↓lijiawei255/dsh-status-chime
分享 · DeepSeek Harness Hub
lijiawei255/dsh-status-chime

用声音长短区分任务紧急程度,离开屏幕也能听见

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部