dsh-task-toast
成功/失败提示音 + 桌面通知插件 for DeepSeek Harness (DSH) · Plays long, noticeable system sounds and desktop notifications when a DSH task succeeds or fails — Windows / Linux / macOS.
一个 DSH 事件插件:监听 agent 回合(turn/end)和(可选)工具调用结果(tools/result),在成功和失败时用不同的、更长更醒目的系统提示音 + 可选的桌面通知 + 可选语音播报告知当前状态,让你不盯屏幕也知道结果。
A DSH events plugin: watches agent turns (turn/end) and (optionally) tool-call results (tools/result), and on success vs failure plays distinct, longer system sounds plus optional desktop notification and optional spoken announcement — know the result without watching the screen.
零运行时 npm 依赖:只使用宿主传入的 ctx 与 Node 内建 node:child_process(由平台命令播放声音 / 弹通知 / 语音播报)。所有 @deepseek-ai/* 均为 import type,编译期擦除。
Zero runtime npm dependencies: only the host-provided ctx and the Node builtin node:child_process (the platform command runs sounds / notifications / speech). All @deepseek-ai/* imports are import type — erased at compile time.
功能 / Features
| 场景 / Scenario | 默认提示音 / Default sound | 桌面通知 |
|---|
回合成功 turn/end reason=completed | chimes(更长钟声) | ✅「任务成功」 |
回合失败 turn/end reason=error | hand(错误/关键停止音) | ✅「任务失败」 |
回合被打断/阻塞/超长 aborted blocked max-tokens interrupted | 静音(可配置 otherSound) | — |
| 工具调用成功/失败(`mode: 'tool' | 'both'` 时) | 同上 success/failure 音(不弹通知,避免刷屏) |
更醒目可选三件套 / Three levers to make it more noticeable:
- 换更长的音 —
chimes / tada / ringout / notify,或任意音频文件路径
- 重复播放 —
repeat: 2 | 3,每次间隔 ~300ms,更长更刺耳
- 通知 + 语音 —
toast: true(默认)弹桌面通知;speak: true 用 TTS 播报结果
跨平台支持 / Platform support
三个平台使用同一套配置与声音名,各自映射到系统资源:
| 能力 | Windows | Linux | macOS |
|---|
| 声音来源 | AppEvents 注册表方案 + C:\Windows\Media\*.wav | freedesktop 主题 /usr/share/sounds/freedesktop/stereo/*.oga | /System/Library/Sounds/*.aiff |
| 播放器 | powershell.exe + Media.SoundPlayer | paplay → aplay → mpv → ffplay(自动探测) | afplay |
| 桌面通知 | Windows Toast(PowerShell WinRT) | notify-send | osascript display notification |
| TTS 语音 | SAPI(SAPI.SpVoice) | spd-say → espeak-ng → espeak(探测) | say |
| repeat 循环 | PowerShell 1..N | ForEach-Object | POSIX while + sleep | POSIX while + sleep |
声音名跨平台一致(chimes/hand/tada/notify/ringout/asterisk/beep/exclamation/question/default),配置可移植。找不到对应系统资源时静默跳过,绝不干扰宿主进程。
The same config and sound names work on all three platforms; each is mapped to the platform's native resources. Missing themes/players degrade silently — the harness is never harmed.
快速开始 / Quick start
pnpm install
pnpm run build # tsc -> dist/index.js (pure ESM)
# 在「父目录」执行(相对路径锚定调用目录):
dsh plugin --profile my-profile add ./dsh-task-toast
dsh --profile my-profile
或者作为 bundle 加入 profile(把 dsh-task-toast 加进 profile 的 bundles 即可,插件自带 cordis.patch.yml 会把自身插入配置树)。
Or add as a bundle: list dsh-task-toast in the profile's bundles; the plugin's own cordis.patch.yml inserts it into the config tree.
配置 / Configuration
默认配置即可用;通过 patch 层覆盖(后层按 id 整行替换):
Defaults work out of the box; override through patch layers (whole-row replace by id):
# profile 的 cordis.patch.yml (or a later bundle layer)
- insert:
- id: dsh-task-toast
name: dsh-task-toast
config:
enabled: true # 总开关 (master switch)
mode: turn # turn | tool | both
successSound: chimes # 更长的成功音;或任意音频文件路径
failureSound: hand
otherSound: '' # 静音;可设成 exclamation/question 等
repeat: 2 # 关键!连播次数(间隔 300ms),想更醒目就调大
toast: true # 桌面通知(成功/失败)
speak: false # TTS 播报(需已装对应语言语音包)
minIntervalMs: 1200 # 两次动作(声音/通知/语音)最小间隔
ignoreTools: [] # tool/both 模式下忽略的工具名
支持的 successSound / failureSound / otherSound(各平台映射见上表):
| 名字 / Name | Windows | Linux (freedesktop) | macOS |
|---|
chimes ⭐ | chimes.wav → tada.wav → Windows Ding.wav | complete.oga → bell.oga → message.oga | Glass.aiff → Hero.aiff → Funk.aiff |
tada ⭐ | tada.wav → chimes.wav → notify.wav | complete.oga → bell.oga → message.oga | Funk.aiff → Hero.aiff → Glass.aiff |
notify ⭐ | Windows Notify System Generic.wav → notify.wav → Windows Ding.wav | message.oga → bell.oga → dialog-information.oga | Ping.aiff → Pop.aiff → Tink.aiff |
ringout ⭐ | Windows Ringout.wav → Ring01.wav → notify.wav | phone.oga → bell.oga → message.oga | Funk.aiff → Ping.aiff → Pop.aiff |
hand | Windows Foreground.wav → Windows Error.wav → Windows Critical Stop.wav | dialog-error.oga → dialog-warning.oga → bell.oga | Sosumi.aiff → Basso.aiff → Frog.aiff |
asterisk | SystemAsterisk 方案 | dialog-information.oga → bell.oga → message.oga | Glass.aiff → Ping.aiff → Pop.aiff |
exclamation | SystemExclamation 方案 | dialog-warning.oga → dialog-information.oga | Basso.aiff → Blow.aiff |
question | SystemQuestion 方案 | dialog-question.oga → bell.oga | Purr.aiff → Tink.aiff |
beep / default | SystemDefault 方案 | bell.oga → dialog-information.oga | Pop.aiff → Tink.aiff |
| 任意音频文件路径 | 直接播放 | 直接播放 | 直接播放 |
⭐ = 更长 / 更醒目选项(推荐成功音用 chimes 或 tada)
项目结构 / Layout
src/index.ts # 插件源码(apply + 纯函数:三平台命令生成器)
cordis.patch.yml # bundle 补丁层(默认配置)
test/index.test.mjs # 单元测试(纯逻辑,三平台命令断言)
test/integration.mjs # 集成测试(真实 Cordis fiber + 事件总线)
scripts/play-sounds.mjs # 手动试听:node scripts/play-sounds.mjs
scripts/toast-demo.mjs # Toast 演示:成功+失败各弹一次通知
开发 / Development
npm run build # tsc -> dist/index.js
npm test # 单元测试(in-process,不需要声音设备;含三平台命令断言)
node test/integration.mjs # 真实 Cordis Context 装载 + 事件触发(会真播放声音/弹通知)
node scripts/play-sounds.mjs # 试听默认成功/失败/自定义声音
node scripts/toast-demo.mjs # 弹一次成功 + 一次失败 Toast
集成测试会真实播放提示音并弹通知,请确定喇叭开着。生成的 POSIX 命令已用 sh -n 语法校验。
依赖版本 / Pinned versions
- runtime deps: none
@deepseek-ai/dsh-tools / @deepseek-ai/dsh-session: 0.1.0-rc.7(对齐宿主运行时,devDependencies,仅类型)
@deepseek-ai/cordis: ^4.0.1(peerDependency,宿主提供)
- Node
^22.19.0 || >=24.0.0
坑 / Pitfalls
@deepseek-ai/dsh-tools 的 npm latest 是过期线(0.0.1-rc.1),正确线在 next tag。本项目对齐宿主运行时锁 0.1.0-rc.7,勿用 npm i @deepseek-ai/dsh-tools 覆盖。
- 纯 ESM:
"type": "module",module: esnext + moduleResolution: bundler。
@deepseek-ai/cordis 只 import type;运行时 ctx 由宿主传入。
- 注册即 effect:
ctx.on(...) 卸载自动清理,集成测试已验证 fiber dispose 干净。
- Windows 用 PowerShell 5.1 语法(无三元表达式);Linux/macOS 用 POSIX
sh(无 bash 专属特性,未发现 paplay/aplay 时静默跳过)。
- Toast 通过 PowerShell AUMID 弹出(Windows);Linux 需要
notify-send(libnotify),macOS 需要 osascript。任一缺失都静默失败不影响 DSH。
speak: true 依赖已安装的 TTS 语音包;没有时静默失败(try/catch / command -v 探测)。
License
MIT