DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

6-debug-6 /

6-debug-6/dsh-thinking-notifier

Verified

A simple popup that can quickly show when Deepseek has finished thinking or is requesting permission during split-screen.

★ 4 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@7f12b741

dsh-thinking-notifier

A DeepSeek Harness (DSH) plugin that shows a small always-on-top desktop popup in the bottom-right corner of your screen. It mirrors the AI's thinking status in real time and alerts you when the AI requests permission, waits for a choice from you, or finishes thinking — even when you are working in other apps, browsers, or virtual desktops.

中文说明见 README.zh.md

Features

State Popup Sound
AI is thinking DeepSeek-blue pulsing dot + AI 正在思考… + elapsed time. Auto-collapses to a 25 px slim right-edge tab after 5 s; hover or click the tab to expand it again none
AI waits for your choice Violet pulsing dot + AI 正在等待你的选择 + the question heading, the first question's option labels (选项:A / B, (可多选) for multi-select, (共 N 问) when several questions arrive at once) and how long it has been waiting. Stays expanded until you answer system Question
AI requests permission Amber pulsing dot + AI 请求权限 + session/tool name. Stays expanded until you decide system Exclamation
AI finished thinking Green dot + AI 已完成思考, auto-hides after 12 s system Asterisk
Idle Hidden none
  • DeepSeek-style dark card (#1E2235 / #4D6BFE).
  • Always-on-top frameless window, bottom-right, visible over any application.
  • Auto-collapses into a 25 px slim right-edge tab after 5 s while the AI is thinking, so it stays visible without blocking desktop controls.
  • Hover or click the edge tab to expand it manually; new turns, questions, permission requests, and completions expand it automatically.
  • Click the X button to dismiss the current popup; the next new turn, question, permission request, or completion will show it again.
  • Questions are shown with their options, which is enough to know what is being decided; the answer itself is still given in the DSH Web UI (the popup is read-only by design).
  • Multiple sessions are summarized automatically.
  • The popup process stays alive while DSH runs; it exits ~15 s after the status endpoint becomes unreachable.
  • No browser extension required; the popup is a native desktop window.

How it works

DSH process
  └─ lib/index.js (host plugin)
       ├─ listens to session/event: turn/start, turn/end, approval/asked, approval/decided, session/title
       ├─ rebuilds existing session state from ctx.sessions.list() at startup
       │    (a session whose log ends inside an open turn is treated as not running)
       ├─ wraps ctx.userQuestions.ask to observe ask_user_question
       │    (that state produces no session event, and a second UI provider cannot be registered)
       ├─ serves a local status JSON at http://127.0.0.1:7389/status
       └─ launches the desktop popup process
             ├─ Windows: desktop-popup.ps1 (PowerShell + WPF)
             └─ macOS/Linux: desktop-popup.py (Python 3 + tkinter)

Desktop popup
  ├─ polls /status every second
  ├─ renders the DeepSeek-style card (question/pending/running/done/idle)
  ├─ plays a system sound on question/pending/done transitions
  ├─ auto-collapses to the right edge while running; stays expanded while waiting for you
  └─ hides while idle, keeps running in the background

Status JSON

GET http://127.0.0.1:7389/status returns:

{
  "ok": true,
  "mode": "question",
  "statusText": "AI 正在等待你的选择",
  "sessionText": "Choose Mode",
  "detailText": "选项:样式 A / 样式 B(可多选)",
  "timeText": "已等待 00:12",
  "pendingKind": "question",
  "pendingTool": null,
  "runningSince": null,
  "doneAt": null,
  "questionCount": 1,
  "questionSince": 1791374946369,
  "appUrl": "http://127.0.0.1:3080",
  "now": 1791374946369
}

mode priority: pending (an approval is waiting) > question (a question is waiting) > running > done (shown for 12 s) > idle. pendingKind is approval or question. timeText is the thinking timer while running and the waiting time while question; detailText carries the first question's options.

Installation

From a local checkout

cd dsh-thinking-notifier
dsh plugin --profile web add .

# Restart DSH web so the host plugin is loaded
dsh web

From npm (once published)

dsh plugin --profile web add dsh-thinking-notifier
dsh web

Uninstall

dsh plugin --profile web remove dsh-thinking-notifier

Configuration

Environment variable Default Description
DSH_THINKING_NOTIFIER_PORT 7389 Local status server port. If busy, the next 10 ports are tried.
DSH_THINKING_NOTIFIER_NO_POPUP unset Set to 1 to run the status server without launching the desktop popup (headless, tests).

Requirements

  • DeepSeek Harness Web UI (dsh web)
  • Node.js ^22.19.0 || >=24.0.0
  • Windows: Windows 10/11 with PowerShell 5.1+ (built in)
  • macOS/Linux: Python 3 with tkinter

Verification status

Being explicit about what has actually been tested, so nobody is surprised:

Area Status
Thinking / done states, popup geometry, sounds, single instance verified on Windows 10/11 (PowerShell 5.1 + WPF)
Question state (ask_user_question) verified end to end in a live DSH session (a real question drove the popup into the waiting state, and it cleared when the answer arrived), against the real ctx.userQuestions service in a cordis context, and by the smoke test
Permission alert (amber) verified only with the mock status service. On a Windows DSH install without a confining sandbox, an out-of-workspace write is not intercepted, so no approval is raised by the runtime; the request only appears when a tool call explicitly asks for a sandbox_permissions escalation or a pre-execute hook returns ask
desktop-popup.py (macOS/Linux) never run on real hardware — syntax-checked only
Popup process stacking after repeated dsh web restarts the launcher kills stale popups for its own port before starting a new one; verified for a single restart cycle

Development

# status-machine smoke test (fake cordis context, no popup, port 17389)
npm test

# render the popup against a mock status service, on a spare port
node tools/mock-status.mjs question --port 17389
powershell -NoProfile -ExecutionPolicy Bypass -File desktop-popup.ps1 -Port 17389   # Windows
python3 desktop-popup.py --port 17389                                               # macOS/Linux

Use a spare port for popup experiments: the real popup on 7389 is left alone, because the plugin only cleans up popup processes belonging to its own port.

Project structure

dsh-thinking-notifier/
├── lib/
│   └── index.js          # host plugin: state machine + status service + popup launcher
├── desktop-popup.ps1     # Windows native popup (PowerShell + WPF)
├── desktop-popup.py      # macOS/Linux native popup (Python 3 + tkinter)
├── cordis.patch.yml      # DSH bundle patch for persistent mounting
├── test/
│   └── status-smoke.mjs  # status-machine smoke test
├── tools/
│   └── mock-status.mjs   # mock status service for offline popup testing
├── package.json          # npm package + dsh.bundle declaration
├── README.md             # English readme
├── README.zh.md          # Chinese readme
├── CHANGELOG.md
├── CONTRIBUTING.md
└── LICENSE

Troubleshooting

Debug logs are written to:

  • ~/.dsh/tn-plugin.log — host plugin lifecycle, popup launcher, question watcher.
  • ~/.dsh/tn-launcher.log — PID of the popup process created by the launcher.
  • ~/.dsh/tn-popup-debug.log — popup script lifecycle and polling errors.

If the popup does not appear after restarting dsh web, check those logs first. Note that popup launcher exit: code=0 in tn-plugin.log is expected: the plugin spawns a one-shot launcher which starts the real popup process and then exits.

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 7f12b7411bc6

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout