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

启动完成音效 boring-cuzzz/dsh-chimes

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

为桌面版添加开场与任务完成提示音

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

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

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add boring-cuzzz/dsh-chimes
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · desktop
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 26 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-chimes(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/9 17:36:13

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

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

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 35 处,展示前 35 条)
  • 发起网络请求
    lib/client.js:125
    const response = await fetch(path, init)
  • 发起网络请求
    lib/client.js:278
    const response = await fetch(
  • 读取本地文件
    lib/routes.js:185
    if (next !== null && !existsSync(next)) return sendJson(res, 400, { ok: false, error: 'that audio file does not exist' })
  • 读取本地文件
    lib/routes.js:230
    const wav = requested !== null && existsSync(requested) ? requested : resolveWavPath(kind, settings, pluginDir)
  • 删除本地文件
    lib/routes.js:316
    rmSync(join(assetsDir(), USER_FILE[kind]), { force: true })
  • 删除本地文件
    lib/routes.js:317
    rmSync(join(assetsDir(), PREV_FILE[kind]), { force: true })
  • 读取本地文件
    lib/routes.js:340
    if (previous !== '' && !existsSync(previous)) {
  • 读取本地文件
    lib/player.js:47
    const stats = statSync(logPath, { throwIfNoEntry: false })
  • 写入本地文件
    lib/player.js:48
    if (stats !== undefined && stats.size > LOG_LIMIT_BYTES) writeFileSync(logPath, '')
  • 写入本地文件
    lib/player.js:49
    appendFileSync(logPath, `${new Date().toISOString()} pid=${process.pid} ${message}\n`)
  • 读取本地文件
    lib/player.js:67
    if (!existsSync(wavPath)) {
  • 执行外部命令来自配置/变量
    lib/player.js:72
    const child = spawn(
  • 读取本地文件
    lib/state.js:36
    if (!existsSync(STATE_PATH)) return {}
  • 读取本地文件
    lib/state.js:37
    const parsed = JSON.parse(readFileSync(STATE_PATH, 'utf8'))
  • 写入本地文件
    lib/state.js:59
    mkdirSync(dirname(STATE_PATH), { recursive: true })
  • 写入本地文件
    lib/state.js:61
    writeFileSync(temp, `${JSON.stringify(state, void 0, 2)}\n`)
  • 写入本地文件
    lib/state.js:62
    renameSync(temp, STATE_PATH)
  • 读取本地文件
    lib/assets.js:35
    if (typeof settings?.wavPath === 'string' && settings.wavPath.trim() !== '' && existsSync(settings.wavPath)) {
  • 读取本地文件
    lib/assets.js:39
    if (existsSync(user)) return user
  • 读取本地文件
    lib/assets.js:51
    if (typeof wavPath !== 'string' || wavPath === '' || !existsSync(wavPath)) {
  • 读取本地文件
    lib/assets.js:54
    const stats = statSync(wavPath)
  • 读取本地文件
    lib/library.js:53
    if (!existsSync(dir)) return []
  • 读取本地文件
    lib/library.js:54
    return readdirSync(dir)
  • 读取本地文件
    lib/library.js:105
    while (existsSync(candidate)) {
  • 写入本地文件
    lib/library.js:123
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/library.js:126
    writeFileSync(temp, buffer)
  • 删除本地文件
    lib/library.js:128
    rmSync(target, { force: true })
  • 写入本地文件
    lib/library.js:129
    copyFileSync(temp, target)
  • 删除本地文件
    lib/library.js:131
    rmSync(temp, { force: true })
  • 读取本地文件
    lib/library.js:154
    if (!existsSync(source)) return { ok: false, error: 'file not found' }
  • 写入本地文件
    lib/library.js:164
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/library.js:166
    renameSync(source, target)
  • 读取本地文件
    lib/library.js:185
    if (!existsSync(target)) return { ok: false, error: 'file not found' }
  • 读取本地文件
    lib/library.js:187
    const size = statSync(target).size
  • 删除本地文件
    lib/library.js:188
    rmSync(target, { force: true })
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 启动与回合完成提示音
  • 应用内控制面板
  • 可切换音效库

DeepSeek Harness 桌面应用的启动与回合完成提示音,带应用内控制面板和可切换音效库(Windows,零依赖)。

README

由 DeepSeek 最新模型翻译生成
dsh-chimes 给 DeepSeek Harness 桌面版加两个音效:打开软件时播一次开场音,每轮任务完成时播一次提示音。 仓库自带 9 个示例音效(6 个 ffmpeg 合成的 CC0 音调 + 3 个作者挑选并确认无版权争议的音效,开箱默认用的就是后两个),并且支持你自己的音频 —— 面板里有下拉菜单可以随时切换。 仓库刻意不收录任何来源不明的第三方素材,原因见 音效与版权。 它做什么 | 音效 | 触发时机 | 说明 | | 开场音 | 打开桌面版、窗口即将渲染时 | 只在 desktop profile;每次启动一次,插件热重载/刷新界面不会重播 | | 完成音 | 每轮对话正常结束时 | 只在用户会话;子代理/委派会话结束不会响;报错或中断不响 | 两者都是宿主侧播放(通过 Windows 的 System.Media.SoundPlayer),所以: - 不需要窗口在前台 —— 你可以去干别的事,任务跑完照样能听到; - 不受浏览器自动播放策略影响(这也是不用 Web Audio 方案的原因)。
展开完整文档(README 剩余 1 节)
dsh-chimes

给 DeepSeek Harness 桌面版加两个音效:打开软件时播一次开场音,每轮任务完成时播一次提示音。

仓库自带 9 个示例音效(6 个 ffmpeg 合成的 CC0 音调 + 3 个作者挑选并确认无版权争议的音效,开箱默认用的就是后两个),并且支持你自己的音频 —— 面板里有下拉菜单可以随时切换。
仓库刻意不收录任何来源不明的第三方素材,原因见 音效与版权。

它做什么

| 音效 | 触发时机 | 说明 |
| 开场音 | 打开桌面版、窗口即将渲染时 | 只在 desktop profile;每次启动一次,插件热重载/刷新界面不会重播 |
| 完成音 | 每轮对话正常结束时 | 只在用户会话;子代理/委派会话结束不会响;报错或中断不响 |

两者都是宿主侧播放(通过 Windows 的 System.Media.SoundPlayer),所以:

- 不需要窗口在前台 —— 你可以去干别的事,任务跑完照样能听到;
- 不受浏览器自动播放策略影响(这也是不用 Web Audio 方案的原因)。

环境要求

- Windows(依赖 .NET 的 Media.SoundPlayer)
- DSH 桌面版(profile 名 desktop),已至少启动过一次
- PowerShell 5.1+(系统自带)
- ffmpeg —— 仅当你需要转码时(音效本来不是 PCM WAV 才需要);也可以用脚本外自己转好

安装

方式一:一条命令(推荐)

把 boring-cuzzz 换成你的 GitHub 用户名
dsh plugin --profile desktop add github:boring-cuzzz/dsh-chimes

若 Git 地址安装失败(网络/代理原因),改用方式二,效果一样。

方式二:本地路径

git clone https://github.com/boring-cuzzz/dsh-chimes.git
dsh plugin --profile desktop add .\dsh-chimes

装完之后

1. 彻底退出 DSH,再重新打开 → 应该听到开场音;
2. 随手问一句话,等回复结束 → 应该听到完成音。

两个音效默认用的是仓库里的占位音(assets/sample-.wav)。换成你自己的见下一节。

控制面板与音效库

装好后在 侧栏「插件」页 → Chimes(部分核心在 设置 → 插件)里操作,完全不用碰命令行:

| 控件 | 作用 |
| 开场音 / 完成音 开关 | 独立启停,实时生效,不用重启 |
| 音效库下拉菜单 | 在「自带示例」(9 个)与「我的音效」之间切换 |
| 试听 | 走真实播放链路放一遍(不是浏览器里模拟) |
| 选择音频… | 选任意 mp3 / m4a / wav / ogg / flac —— 在浏览器里直接转成 WAV,不需要你装 ffmpeg |
| 删除 | 只允许删「我的音效」里的条目;自带示例受保护 |
| 重命名 | 给你自己的音效起名 —— 名字就是下拉里显示的文字(如"奥德赛开场""小号成功");自带示例不可改名 |
| 撤销 / 恢复默认 | 回到上一次选择 / 回到自带示例音 |

你添加过的音效会一直留在下拉菜单里,以后点一下就能切换,不用重新导入。

它们默认存放在 %USERPROFILE%\.dsh\chimes-library\ —— 在仓库之外,所以不可能被你误提交。

想放到别的盘(例如 C 盘空间紧张)?在 %USERPROFILE%\.dsh\chimes-state.json 里加一行即可,不用改代码:

{ "version": 1, "libraryDir": "D:\\AA素材" }

优先级是:环境变量 DSH_CHIMES_LIBRARY → 这个 libraryDir → 默认的 %USERPROFILE%\.dsh\chimes-library\。
搬家后请把旧目录里的音频拷过去,面板里点一下「刷新」。某个选择指向的文件如果不存在了,插件会回退到别的可用音效而不是变成静音。

换音效(命令行方式,可选)

不想开 GUI 时,一条命令搞定(自动转码 + 掐头静音 + 安装):

powershell -ExecutionPolicy Bypass -File .\scripts\install-chime.ps1
-Startup "D:\我的音效\开场.mp3" -Done "D:\我的音效\完成.mp3"

只想换一个就只传那一个参数;-Volume 0.8 可在转码时调音量。

两条硬限制(面板方式会自动满足,手动方式要注意):

- 必须是 PCM WAV(pcm_s16le)。mp3 改名成 .wav 不会响;
- 音量只能转码时烘焙(ffmpeg -af "volume=1.5"),因为 SoundPlayer 没有音量 API。

细节见 👉 docs/音效与版权.md

配置

两个音效是两个独立的 loader 行,可以分别开关。改 profile 的 cordis.patch.yml:

- insert:
- id: startup-chime
name: dsh-chimes
config:
kind: startup
enabled: true
delayMs: 350 # 界面就绪后再等多久播(调大 = 更晚,可与窗口出现对齐) waitMs: 6000 # 等不到界面就绪时的兜底时限 wavPath: 'D:\我的音效\开场.wav'

- id: done-chime
name: dsh-chimes
config:
kind: done
enabled: true
cooldownMs: 1500 # 两次响之间的最小间隔,防连击 minTurnMs: 0 # 只对耗时超过 N 毫秒的回合响(觉得快问快答太吵就设 5000)
excludeSessionPrefixes: ['session-test']
wavPath: 'D:\我的音效\完成.wav'

临时静音全部音效:设环境变量 DSH_CHIME_MUTE=1。

排障

每次触发都会写一行日志,先看它:

%USERPROFILE%\.dsh\startup-chime.log ← 开场音 %USERPROFILE%\.dsh\done-chime.log ← 完成音

一次正常的开场应该是:

module imported (entry=...)
apply: armed (profile="desktop", wav=...\assets\chime.wav)
poll: webRuntime ready after 472ms
fire: webRuntime ready
PLAYING ...\assets\chime.wav (pid=...)
player exited code=0 after 3497ms ← 活了整段音频的时长 = 真的播完了

| 症状 | 原因 | 处理 |
| 完全没声音,日志里连 module imported 都没有 | 插件没被加载 | 侧栏「插件」页看是否启用;查 dsh.profile.bundles |
| 有 PLAYING 但 player exited 只有几十毫秒 | 音频不是合法 PCM WAV | 重新转码;见 音效与版权 |
| SKIP wav not found | wavPath 不对 | 用绝对路径,确认文件存在 |
| 开场音不响,但日志显示走了 fire: fallback timeout | 没检测到 webRuntime,走了兜底 | 能响只是偏晚;把 delayMs 调小 |
| 完成音在子代理结束时也响 | 不该发生 | 开 issue 并附上会话类型(用户会话/子代理) |
| 装不上、报 profile "desktop" is managed exclusively… | 用了从 npm 另装的独立 dsh | 必须用桌面版自带的启动器:<安装目录>\resources\runtime\cli\bin\dsh.cmd |

安全

- 零网络、零遥测:代码不发起任何网络请求,不读取任何凭据;
- 零依赖、无 postinstall:安装时不会执行任意代码;
- 播放进程只拿到 4 个环境变量,DSH 主进程的 API key 不会传过去;
- 播放器用绝对路径启动,不查 PATH;音频路径经环境变量传入,无命令注入面;
- 详细清单(含 DSH 插件的权限边界说明)见 SECURITY.md。

兼容性

- 实测环境:DSH 桌面版 0.2.0-rc.2 + Windows 11;
- 插件故意不声明任何 peerDependencies,因此不会撞上 DSH 安装期的 peer 版本校验;
- 判断当前 profile 用 ctx.get('profileContext')?.name,只在 desktop 生效;
- 完成音的"非子代理"判断用的是运行时校验过的会话头字段(origin === 'subagent' / delegationDepth / parentSession),不是猜 id 前缀。

许可

- 代码:MIT
- assets/ 下的示例音频:CC0-1.0(公有领域,由 ffmpeg 从正弦波合成,可复现,见 音效与版权)

贡献

欢迎 PR。三条约定(详见 docs/音效与版权.md):

1. 不要提交第三方音频(游戏/影视/音乐/素材库)—— 会造成 DMCA 风险;
2. 提交自制音效请在 PR 里声明"本人创作,同意以 CC0 授权";
3. 改 scripts/.ps1 时保持 UTF-8 带 BOM(否则 PowerShell 5.1 读不了中文,见 .gitattributes)。

相关

- DeepSeek Harness —— 一切皆插件的 agent harness
- GitHub 话题 dsh-plugin —— 社区插件生态
预览分享卡片长什么样 ↓boring-cuzzz/dsh-chimes
分享 · DeepSeek Harness Hub
boring-cuzzz/dsh-chimes

为桌面版添加开场与任务完成提示音

回到顶部