SiriLee/dsh-approval-hotkeys
DeepSeek Harness plugin: approval-panel hotkeys — Enter approves once, Esc rejects, Esc pauses a running agent
项目介绍Project Overview
dsh-approval-hotkeys 是 DeepSeek Harness 的浏览器端插件,绑定 Enter 为确认、Esc 为取消,作用于所有带按钮的交互面板:审批(Allow once / Reject)、提问(Submit / Discard)、计划评审(Approve / Decline)。在频繁出现的审批弹窗中可直接键盘完成,无需鼠标定位。安装后仅需刷新页面,无配置项。注意:按钮通过位置解析,其他插件向面板注入非操作按钮时需标记 data-hotkey="none",否则可能被误识别为确认或取消动作。
dsh-approval-hotkeys is a pure browser-side DeepSeek Harness plugin that maps Enter to the confirm button and Esc to the cancel button across every button-bearing interaction panel: approvals (Allow once / Reject), questions (Submit / Discard), and plan reviews (Approve / Decline). It is useful when repeated approval popups interrupt a workflow, letting the user decide without reaching for the mouse. Install via dsh plugin --profile web add dsh-approval-hotkeys and refresh the page. Caveat: buttons are resolved by position; any plugin injecting a non-action button into a panel must mark it data-hotkey="none", or it may be misidentified as confirm or cancel.
请帮我了解并安装插件:【dsh-approval-hotkeys】【https://github.com/SiriLee/dsh-approval-hotkeys】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin --profile web add dsh-approval-hotkeys
把 SiriLee/dsh-approval-hotkeys 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-approval-hotkeys
Approval-panel hotkeys for DeepSeek Harness, for every approval source — not just edits.
English | 中文
A deliberately minimal plugin with one generic rule: Enter always presses the confirm button (the primary, right-most action); Esc always presses the cancel button — on every button-bearing interaction panel the harness renders.
| Panel | Enter → confirm | Esc → cancel |
|---|---|---|
Approval ([data-approval-key]) |
Allow once | Reject |
Question / choice ([data-question-key]) |
Submit / Next | Discard the group |
Plan review ([data-plan-review-key]) |
Approve | Decline (or discuss) |
The panel anchors are harness-generic, so the hotkeys work on every interaction the GUI shows — edit approvals, permission escalations, tool questions, plan reviews. This is the Claude Code habit: confirm with Enter, refuse with Esc.
Approval panel
Every approval — edits, permission escalations, anything routed through the ApprovalPanel. Enter presses Allow once, Esc presses Reject.
Question / choice panel
Tool questions (ask_user_question). Enter presses Submit / Next,
Esc presses Discard the group.
Plan review panel
Enter presses Approve, Esc presses Decline (or Discuss when the panel has no decline action).
Install
dsh plugin --profile web add dsh-approval-hotkeys
Restart dsh web — or, since this plugin is pure browser-side, just refresh the page when the host side did not change. No configuration, no settings page.
For contributors: install from a local checkout or a pinned commit — dsh plugin --profile web add /path/to/dsh-approval-hotkeys or dsh plugin --profile web add github:SiriLee/dsh-approval-hotkeys#<sha>. A git install fails on first run until you add an allowBuilds key to the profile's pnpm-workspace.yaml (pnpm blocks git dependencies from running build scripts); after that it runs the plugin's prepare and installs it.
How it works
- Enter → confirm: clicks the panel's primary button — the last button
of its action row ("Allow once", "Submit/Next", "Approve"). The harness's
Buttoncomponent has no stabledata-variantattribute (variants are CSS-Modules hash classes), so the plugin anchors on the layout contract that the confirm action always renders last — which is exactly the primary-colored button. - Esc → cancel: clicks the panel's cancel button — Reject (first), Discard (header), Decline (footer second-last, or Discuss when the panel has no decline action). Without a panel, Esc is left alone (no pause/stop binding — the GUI's own stop button and shortcuts own that).
Guards (what the plugin deliberately does NOT do)
- Never while typing: keydown inside an input / textarea / select /
contentEditable (the composer owns
Enter/Escthere — e.g.Shift+Enternewline,Escdismisses suggestions). - Enter with focus on a button: left to the browser (it activates the focused button natively) and to the panel itself (the question composer's options submit on Enter) — acting again would double-fire.
- Never on chords or repeats:
Ctrl/Meta/Alt+keycombinations and held-key repeats are left alone. - Esc with no panel: left alone — the plugin never stops or pauses the agent; panels are the only surface it acts on.
Button resolution contract (data-hotkey="none")
Enter/Esc resolve their buttons by position (first / last / header-last /
footer-last), not by a stable semantic attribute — the harness's Button
component exposes no reliable data-role/data-variant, so position is the
only stable signal available to a client plugin that does not own the panel
DOM. That makes button order the single coupling point to the harness layout.
To keep that coupling safe when other plugins inject buttons into a panel
(utility toggles, decorative controls), this plugin skips any button marked
data-hotkey="none" when resolving the confirm/cancel action. Any plugin that
adds a non-action button into an interaction panel should mark it:
<button data-hotkey="none">Collapse diff</button>
This is a cooperative, opt-out contract, not a hard guarantee. It reliably covers "a plugin inserts an extra non-action button ahead of the action row" (such as dsh-edit-approval's diff collapse toggle). It does not cover:
- a plugin that injects a button without the marker (contract ignored), or
- a plugin that reorders / inserts a genuinely actionable button among the real confirm/cancel buttons (the semantics changed, not just a decoration added), or
- a change to the harness's own panel layout.
Those cases need a stable semantic anchor in the harness panel DOM (e.g.
data-role="confirm" / data-role="cancel") — a harness-repo change, not a
client-plugin fix. File an issue / PR against deepseek-harness if it bites.
Design notes
- Pure browser (client) plugin: the host half is a no-op stub. All behavior
is a single
documentkeydownlistener registered inside onectx.effect, torn down on unload/HMR. - Relies on the stable ApprovalPanel DOM contract: reject renders first,
allow-once last, both
disabledafter an answer — so a double-answer is impossible and the button-order dependency is the only harness coupling. - The panel lookup prefers the current session's pending approval key and falls back to the first panel in DOM order.
Development
npm install
npm run typecheck # tsc --noEmit (host + client)
npm test # vitest (jsdom unit tests for the dispatch logic)
npm run build # esbuild: lib/index.js + lib/client.js + .d.ts
node scripts/verify-host.mjs
Release
The first publish is manual (npm publish --access public), then the
GitHub Actions Trusted Publishing workflow takes over — push a v<semver>
tag and CI publishes with provenance. Full steps: docs/release.md.
Security
Pure browser-side plugin: the host half is an empty stub, and all behavior is a document-level keydown listener that clicks existing panel buttons. No network requests, no file access, no credentials.
nexu-io/open-design
ruvnet/ruflo
amruthpillai/reactive-resume
volcengine/OpenViking
Molunerfinn/PicGo
titanwings/colleague-skill
nocobase/nocobase
Tencent/WeKnora