Back to home@jensentsts

dsh-completion-sound

Notify after deepseek harness finishes your work. DSH完成工作后提醒。

Stars
0
Language
TypeScript
Created
Aug 17, 2026
Updated
Aug 17, 2026
GitHub repo

Introduction

dsh-completion-sound

A DSH (DeepSeek Harness) completion-sound bundle: plays a chime when an agent turn finishes; plays the special "Guan Yu's Song" music and shows a click-to-stop modal when a long task (≥ 10 minutes by default) finishes; optionally fires a desktop notification (browser notification first, with an automatic fallback to a system notification).

Package: @jensentsts/dsh-completion-sound · Version: 0.1.0 · License: MIT

English | 中文

Settings page

Completion-sound settings page

Installation

dsh plugin --profile web add github:jensentsts/dsh-completion-sound

Replace web with the profile you want to install into. Build artifacts (lib/) are committed, so installing from git needs no pnpm build authorization (pnpm ≥10 allowBuilds); it works right after dsh plugin add.

Pin a commit so later pushes cannot silently change what runs: dsh plugin --profile web add github:jensentsts/dsh-completion-sound#<sha>

Uninstall:

dsh plugin --profile web remove @jensentsts/dsh-completion-sound

⚠️ Installing a plugin runs third-party code on your machine with your own permissions. Review the source before you install.

Relationship to the built-in completion sound

The dsh-web-app bundle ships a built-in completion-sound row (ui-completion-sound@deepseek-ai/dsh-client-ui-completion-sound). This bundle's cordis.patch.yml disables that built-in row and inserts its own row (id completion-sound), so when a web profile has both dsh-web-app and this plugin, this plugin takes over completion sounds and nothing plays twice. In a profile without dsh-web-app, the disable step is silently skipped and the insert still applies.

Features

  • Completion chime: a WebAudio-synthesized two-tone chime (E5 → A5) when a turn finishes
  • Long-task special music: plays special music and shows a modal when a long task finishes; click anywhere to stop
  • Custom special music: point at a single audio file, or a directory (one random track is picked per play)
  • Bundled audio: defaults to the bundled "Guan Yu's Song" (assets/guan-yu.wav, ~13.5 MB)
  • Configurable long-task threshold: 1 minute ~ 10080 minutes (7 days)
  • Desktop notification: optional, cross-platform — browser notification first, automatic fallback to a system notification (macOS osascript / Linux notify-send)
  • Dedicated settings page: everything lives under "Settings → Completion sound"

Settings

FieldDescriptionDefaultRange
enabledcompletion-sound toggletrue
notifydesktop-notification togglefalse
volumevolume0.50–1
longTaskMinuteslong-task threshold (minutes)101–10080
specialplay special music on long-task completiontrue
specialPathspecial-music file/directory path (empty = bundled Guan Yu's Song)""

Special music semantics

specialPath decides what plays when a long task completes:

  • Empty string → the bundled assets/guan-yu.wav
  • File path → that file (content-type derived from the extension)
  • Directory path → recursively scans audio files (.aac .flac .m4a .mp3 .oga .ogg .opus .wav .webm, up to 512), picking one at random per play

The special-music preview button sits to the left of the "music file or directory" input; it commits the path before previewing, so it always previews what is currently typed.

Directory structure

completion-sound/
├── assets/
│   └── guan-yu.wav              # bundled "Guan Yu's Song" (~13.5 MB)
├── img/
│   └── settings.png             # settings-page screenshot
├── src/
│   ├── index.ts                 # Host half: settings schema + audio/notify routes
│   ├── settings.ts              # setting field constants and types
│   ├── invariant.ts             # internal assertions (invariant companion)
│   ├── css-modules.d.ts         # CSS Modules type declarations
│   └── client/
│       ├── index.ts             # Client half: settings binding + completion watch + page registration
│       ├── CompletionSoundSection.tsx  # dedicated settings-page component
│       ├── CompletionSoundSection.module.css
│       ├── settings-store.ts    # settings store (defineStore)
│       ├── sound.ts             # WebAudio synth / audio load & play / stop control
│       ├── notify.ts            # desktop notification (browser-first + system fallback)
│       ├── stop-modal.tsx       # click-to-stop modal
│       ├── stop-modal.module.css
│       └── locales.ts           # zh/en strings
├── lib/                         # build artifacts (committed; git install needs no build)
│   ├── index.js                 # Host half
│   ├── invariant.js
│   ├── client.js                # Client half (browser bundle)
│   └── types/**/*.d.ts          # type declarations
├── package.json
├── cordis.patch.yml             # bundle patch (disable built-in row + insert this plugin's row)
├── tsconfig.json
├── tsdown.config.ts
├── LICENSE
├── README.md
└── README.zh.md

Architecture

This plugin is a DSH bundle: package.json's dsh.bundle.patch points at cordis.patch.yml, and it also declares dsh.client (platform web) so the module loader serves the client half to the browser.

  • Host half (src/index.ts): registers the settings schema and three routes:
    • /completion-sound/guan-yu.wav — bundled Guan Yu's Song (memory-cached, served as audio/wav)
    • /completion-sound/special — serves special music by specialPath (empty→bundled; file→served; directory→one random pick, with header x-dsh-completion-sound-random: 1)
    • /completion-sound/notify — POST system-notification fallback (macOS osascript / Linux notify-send) for when browser notifications are unavailable
  • Client half (src/client/index.ts): binds settings, watches turn-completion events, and registers the settings.section (id completion-sound) dedicated page.

Building

Build artifacts are committed; ordinary users don't need to build. Developers rebuild after editing src/:

pnpm install
pnpm run build      # tsc -p tsconfig.json && tsdown
pnpm run typecheck  # tsc -p tsconfig.json --noEmit

Artifacts (lib/, committed):

  • lib/index.js — host half
  • lib/invariant.js — invariant companion
  • lib/client.js — client half (browser bundle)
  • lib/types/**/*.d.ts — type declarations

tsdown.config.ts is self-contained (it inlines the platform module table, the CSS Modules inline plugin, and the __ModuleLoader__ format); it depends on no monorepo preset.

Dependencies

  • dependencies: runtime value dependencies (@deepseek-ai/dsh-settings, @deepseek-ai/schemastery, react, react-dom)
  • peerDependencies: services provided by the host DSH profile (@deepseek-ai/cordis, dsh-api-remotes, dsh-client-*, dsh-invariants), aligned to 0.1.0-rc.6
  • devDependencies: type-check and build tooling (TypeScript, tsdown, tsx, lightningcss)

System notification dependencies

The system-notification fallback requires notify-send on Linux (libnotify-bin, present on most desktop distros) and the built-in osascript on macOS. Browser notifications are used when available, so the fallback is not hit there.

License

MIT — see LICENSE.