# dsh-windows-notify > Windows native toast notifications for **DeepSeek Harness** (`dsh`). Get a desktop notification when the agent **needs your permission**, **needs you to choose an option**, or **finishes a turn** — then click it to jump straight back to the already-open DSH window. The plugin only *reminds*. The approval card and the option list still live in the web UI — notifications never answer on your behalf. **Platform:** Windows 10/11 only. The host half returns early on other platforms. [中文文档](README.md) ## Features | Moment | Notification | Setting | |---|---|---| | A tool needs approval (`approval/request`) | `DSH 需要你的授权` + tool name + reason | `approval` | | A branch / option must be chosen (`user-questions/request`) | `DSH
` + question + up to 6 option labels | `choice` | | A turn finishes (`agent/status` idle after `session/event` `turn/end`) | `DSH 任务完成` | `completion` | | Click any notification | raises the existing DSH browser window (opens one only if none exists) | `focusOnClick` | | Every turn | standing system-prompt rule: write todo status back **one item at a time**, never batch | `todoStatusPolicy` | | — | master switch; silences all three notifications | `enabled` | ## Requirements - Windows 10/11 - `dsh` with a profile that mounts the web app (`web`) - Windows PowerShell 5.1 (ships with Windows) ## Install 1. Clone it next to your other out-of-tree plugins: ```powershell git clone https://github.com/Exynos671/dsh-windows-notify.git "$env:USERPROFILE\.dsh\profiles\plugins\dsh-windows-notify" ``` 2. Expose the package under `profiles\node_modules` — this junction is what dsh's module resolution expects: ```powershell New-Item -ItemType Junction ` -Path "$env:USERPROFILE\.dsh\profiles\node_modules\@deepseek-ai\dsh-windows-notify" ` -Target "$env:USERPROFILE\.dsh\profiles\plugins\dsh-windows-notify" ``` 3. Mount the plugin. Append this to `~\.dsh\profiles\web\cordis.patch.yml` (or to the home-level `~\.dsh\cordis.patch.yml` to apply it to every profile): ```yaml - insert: - id: windows-notify name: '@deepseek-ai/dsh-windows-notify' ``` 4. Restart dsh (or let `patchReload: live` pick up the patch). **Settings → General → "Windows 通知"** now shows the switches. ### Alternative: install as a bundle The package declares `dsh.bundle.patch`, so it can also be installed as a bundle layer: ```powershell dsh plugin --profile web add github:Exynos671/dsh-windows-notify ``` Do **not** use both routes at once: the manual row above plus a bundle install would mount the package twice, which the client module system rejects. ## Settings Settings live in the `dsh-notify` namespace, are persisted to `~\.dsh\settings.yaml`, and take effect immediately. Toggle them from **Settings → General → "Windows 通知"**, or edit by hand: ```yaml dsh-notify: enabled: true approval: true choice: true completion: true focusOnClick: true todoStatusPolicy: true ``` `enabled: false` silences the three notifications but keeps the plugin mounted (and keeps the standing todo rule). To unload everything, remove or disable the loader row: ```yaml - insert: - id: windows-notify name: '@deepseek-ai/dsh-windows-notify' disabled: true ``` ## How it works - **Read-only observers.** Every listener calls `next()` and returns the request to the web UI's responder. If a plugin answered a permission or question waterfall first, the web UI would stop rendering its card — this one never does. - **Root event bus.** A profile-patch plugin is mounted inside the agent preset's scope, but `approval/request` and `user-questions/request` are dispatched on the *root* event service, so listeners attach to `ctx.root.events`. An `internal/dispatch` observer acts as a scope-rule-free fallback, and a dedupe set guarantees exactly one notification per request. - **Native toast.** The host half shells out to the bundled ASCII-only PowerShell scripts; user-facing text is passed base64 because Windows PowerShell 5.1 reads BOM-less UTF-8 as ANSI and would corrupt Chinese. - **AUMID + URI scheme.** `ensure-aumid.ps1` creates a Start-Menu shortcut carrying an AppUserModelID (`DeepSeekHarness.Notify`) and registers the `dsh-notify:` protocol — this is what lets Windows deliver the toasts and lets a click raise the window. - **Click to focus.** `focus-window.ps1` enumerates top-level windows, prefers a title match (`DeepSeek Harness`), restores it and calls `SetForegroundWindow`; it opens a new tab only when no matching window exists. ## File layout ``` index.mjs host half (Cordis plugin): events, settings schema, system-prompt rule client.js browser half: the Settings → General row and its CSS package.json dsh bundle / client manifest cordis.patch.yml bundle patch (the loader row) toast.ps1 raises one Windows toast ensure-aumid.ps1 creates the AUMID shortcut + URI scheme focus-window.ps1 focuses (or opens) the DSH browser window test/ boot-loader and settings tests ``` ## Development ```powershell node test/notify-settings.test.mjs ``` ## Notes - The package name `@deepseek-ai/dsh-windows-notify` is kept verbatim on purpose: the browser half registers that exact id, and the boot loader rejects a bundle that does not register its own row id. ## License MIT