DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Approval Explainer — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
A

dsh-approval-explainer

Approval Explainer

DSH 审批弹窗 AI 注释器:在模型请求权限外操作时,用模型自己的推理生成「这段代码做什么 / 想达成什么 / 风险评估 / 两个选项各自意味着什么」,让用户带着依据做决定,而不是瞪着一行代码点按钮。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:ArisuYuuko/dsh-approval-explainer#5d8de3dc29894bdb1b88ab62e17138d6c8aec2c8
README兼容性版本

兼容性与来源证明

Approval Explainer 以 dsh-approval-explainer 发布,当前版本为 0.6.1。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/13

版本

0.6.1stable
2026/10/13

相关插件

正在加载相关插件…

最新版
0.6.1
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/15
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 security-access 分类下经过校验的插件。

Experimental Auto Review@deepseek-ai/dsh-experimental-auto-review针对每个工具的 LLM 授权审查,适用于 DeepSeek Harness Auto 权限预设Cc Safety Netcc-safety-net编码代理 CLI 钩子——阻止破坏性命令和访问机密文件Doctor@linxin666/dsh-doctorDSH 配置档案的事务性救援模式,配备受监督的启动器、隔离的恢复容器、确定性修复、健康监控以及本地 Web 恢复控制台Pocketdsh-pocket把 DeepSeek Harness 装进你的口袋:一个包、一个设置页,手机扫码即同步访问电脑上的 DSH(局域网 + 公网,实时同屏)。

README

DSH Approval Explainer

English | 中文

An AI annotator for the approval dialog in DeepSeek Harness (dsh).

When the model asks to run something outside your workspace, dsh shows an approval prompt. This plugin adds an explanation next to the command, generated from the model's own reasoning: what the code does, what the model is trying to achieve, how risky it is and why, and what each button actually means.

Install

dsh plugin --profile desktop add github:ArisuYuuko/dsh-approval-explainer

desktop is the profile the desktop app boots. The first use of a profile initializes it.

Then fully quit and reopen DSH. Reloading the page is not enough: the host half loads only at process start.

Verify the layer was installed:

dsh --profile desktop --dump-config
# == dsh-approval-explainer
- id: dsh-approval-explainer
  name: dsh-approval-explainer
  inject:
    - llm
    - approval

This plugin is plain JavaScript with no build step, so pnpm does not ask you to authorize allowBuilds. See Install notes.

To remove it, along with its configuration layer:

dsh plugin --profile desktop remove dsh-approval-explainer

What it does

Without the plugin an approval prompt shows only the command:

即将执行
& '<temp>\diagnose-windows-sandbox-acl.ps1' -Path 'D:\some-project' -AllowRewrite

You have to work out what it does, what it touches, and what happens if you accept. If you cannot, you are choosing between trusting blindly and refusing blindly.

The plugin adds this to the same prompt:

Risk = medium (confidence high)

[What this code does]
  Writes ~300 words of acceptance notes to <output dir>\note.txt outside the
  workspace, using danger-full-access (cwd is <project dir>). The text itself
  only describes a timeout fix and its measurements.

[What the model is trying to achieve]
  You explicitly asked it to file an escalation request, so the model
  deliberately writes outside the workspace to trigger a real approval prompt
  and measure annotation latency.

[Why this risk level]
  The content is harmless and this is not production, but it explicitly asks
  for danger-full-access and targets a path outside the workspace. That falls
  under permission and security controls, so the standard rating is medium.

[Recommendation]
  Approve once: the content is harmless and matches your instruction, but let
  it through only this time rather than granting standing full-disk access.

[What each option means]
  Approve once -> the text is really written to <output dir>\note.txt and stays
                  on disk until you delete it; other writes under the same grant
                  are also allowed.
  Deny         -> nothing is written and the latency check cannot complete; the
                  model is told it was denied and may retry inside the workspace
                  or stop and ask you.

Note the last block. It does not just say "the command will run" — it says the file will really be created, that it can be deleted, and that other writes are covered by the same grant. That is the information a decision needs.

Design notes

Only real approvalsNo annotations for routine tool calls. In one measurement approval/request fired 2 times while tools/pre-execute fired 259 — annotating everything is the same as annotating nothing
Never blocks approvalGeneration runs in the background; the prompt appears immediately. A failure or timeout cannot affect what you may approve
Failures are visibleWhen generation fails the panel shows why instead of hanging silently
Arguments come from the sessionTool arguments are looked up by callId in the session log, with three fallbacks. If they cannot be found the annotation says so instead of inventing them
Prompt-injection resistantThe system prompt states that code, paths, and commands are data, not instructions
Does not change policyIt observes the approval waterfall; it does not decide who may be authorized

How it works

The plugin is a DSH bundle: an npm package carrying a cordis.patch.yml that contributes one configuration layer to a profile.

package.json        declares dsh.bundle.patch, pointing at the layer file
cordis.patch.yml    the layer: one insert row referencing the package by name
lib/index.js        host half (Node)
lib/client.js       browser half (Web)

The whole install mechanism is five lines of YAML:

- insert:
    - id: dsh-approval-explainer
      name: dsh-approval-explainer     # by package name, so Node resolution finds the installed code
      inject:
        - llm
        - approval

dsh plugin add installs the package into the profile and, because the package declares dsh.bundle, appends it to dsh.profile.bundles. The effective config gains one layer.

The two halves

lib/index.js   host half (Node)
               observes the approval/request waterfall, generates annotations in
               the background via the LLM, caches them, serves 8 HTTP routes

lib/client.js  browser half (Web)
               registers into the conversation.approval.detail slot and renders
               the command plus the annotation card

Key decisions

Only approval/request is hooked. It is the only precise signal for "the user is being asked to decide something right now". An earlier version also hooked tools/pre-execute to pre-generate; the measured signal-to-noise was 259:2, where 259 routine operations drowned the 2 that mattered.

Approval is never blocked. The listener starts background generation and immediately return next(), handing the decision back to the real policy listener. So a successful, failed, or timed-out generation cannot affect what you may approve.

Arguments are looked up in the session log. The approval/request event carries no tool arguments (only toolName, callId, reason), so the plugin finds the tool/call event by callId with three fallbacks (surface.nodes → snapshotEvents() → events). When it cannot, the annotation says arguments are missing rather than inventing them.

Shadowing the official renderer requires an explicit priority. conversation.approval.detail is a single slot, and the official dsh-client-ui-chat already occupies priority: 0. Two registrations at the same priority in one slot is an error, and entriesOfSlot takes the first entry in ascending priority order — so shadowing requires a lower number (-1). The cost is having to re-render the command line yourself.

Two hard constraints

1. Never inject a client bundle yourself. dsh-client-modules deduplicates by URL but rejects duplicate registrations by module id. If the host injects another <script src=".../client.js">, the browser half executes twice, web boot fails, and DSH runs its crash self-heal — which removes profile config and disables every third-party plugin. The startup graph loads the browser half; the host only serves routes.

2. apply() must never throw. Throwing marks the host fiber FAILED, the whole composition fails to mount, and the symptom is "DSH will not start after installing this". Every step in apply() is individually wrapped; any failure is recorded and execution continues.

Diagnostics

http://127.0.0.1:19387/dsh-approval/diag

A check page. Each item carries a conclusion and an action; raw data is folded at the end. Three output formats:

QueryOutput
(none)HTML page for humans
?raw=1Full JSON for scripts
?format=textPlain text for curl

The host also renders an annotation list at /dsh-approval/view without going through the browser half, so annotations remain inspectable even if the browser half misbehaves.

Common problems

No annotation in the prompt. Check /dsh-approval/client. registered: false means the browser half never entered the startup graph; all three conditions must hold — the package is in the startup graph, package.json declares dsh.client.platform === "web", and it exports "./client".

"Annotation could not be generated." The panel footer states the reason: annotation generation timed out (40 s limit), no model route available, or arguments missing.

Changes do not take effect. lib/index.js is the host half — restart DSH. lib/client.js is the browser half — reloading the page suffices.

To tell which revision a running process loaded, compare the moduleFingerprint field of /dsh-approval/diag?raw=1 with the sha256 of the file on disk. Do not use file mtime — any unrelated write moves it forward and the comparison silently flips.

Configuration

Not configurable through cordis.yml today. The tunables are constants at the top of lib/index.js, each with a measured rationale:

ConstantDefaultPurpose
GENERATE_TIMEOUT_MS40000Generation deadline. Measured successes take 5–9 s
ENTRY_TTL_MS600000Annotation cache lifetime
MAX_ARGS_CHARS12000Tool-argument budget fed to the model
MAX_REASONING_CHARS4000Model reasoning budget
MAX_ASSISTANT_TEXT_CHARS2000Model answer budget
MAX_ENTRIES200Cache size cap

Why these are not config fields

The DSH documentation states a convention in Plugin configuration:

No hardcoded tunables — any value a deployment might need to change must be a config field. Test: can you change it in cordis.yml without editing code?

By that test all six should be exported as a Schemastery Config schema. They are not. This is a known deviation, and the reasons are measured rather than assumed:

  1. It requires resolving a peer dependency before apply. Exporting Config needs import Schema from '@deepseek-ai/schemastery', and that package does not resolve from the plugin's own directory (measured: Cannot find module). Only the host runtime's peer resolution can supply it.
  2. The import is evaluated before apply, so the plugin's try/catch cannot cover it. A resolution failure is a module load failure and marks the fiber FAILED — the exact failure class behind this plugin's early crashes.
  3. The convention is a guideline, not a gate. Of six installed bundles on the author's machine, one exports Config; the other five — including a mature 190 KB plugin — do not.

The practical impact is limited: all six defaults are measured and work unchanged. Editing the constants and restarting covers the need.

One invariant if you edit them

lib/client.js polls POLL_LIMIT (120) × POLL_INTERVAL_MS (350 ms). That window must be ≥ GENERATE_TIMEOUT_MS, or the host is still generating while the panel has given up — the annotation is produced and thrown away while the user sees a failure.

The nominal window is 42 s, but the loop requests before it sleeps, so the last request lands at 119 × 350 ms ≈ 41.65 s. Change both values together.

Security

Trust fence. Seven of the eight routes pass through a fence with three checks:

  1. the Host header names a loopback address (localhost, *.localhost, ::1, 127.0.0.0/8)
  2. sec-fetch-site is not cross-site
  3. Origin is either dsh-app: or the same host as Host

It does not check req.socket.remoteAddress — the connection's source address is never inspected. This is not currently exploitable: DSH's web server binds 127.0.0.1 only, so no external source can reach the port, and a same-machine process already has local privileges and has no fence to bypass. If the server ever binds 0.0.0.0, this gap becomes real and source checking must be added.

Annotation text is untrusted. It comes from the model and is HTML-escaped on render. The system prompt also tells the model that code and commands in the material are data, not instructions, to limit prompt injection.

Install notes

Measured by the author under an isolated DSH_HOME, so no real profile was touched:

$ dsh plugin --profile gh add github:ArisuYuuko/dsh-approval-explainer
+ dsh-approval-explainer github:ArisuYuuko/dsh-approval-explainer
Packages: +1
Done in 4.4s using pnpm v11.7.0

$ dsh --profile gh --dump-config
# == dsh-approval-explainer
- id: dsh-approval-explainer
  ...

The resulting pnpm-workspace.yaml contained no allowBuilds entry, confirming no manual authorization was required, and the seven installed files matched the repository byte for byte.

The packaging and installing plugins guide notes that a git install fetches source, not build output, so TypeScript packages need a prepare script plus user authorization. This plugin ships plain JavaScript in lib/, so neither applies. If you are asked for allowBuilds during install, please open an issue — it would mean that reasoning is wrong.

Local paths and tarballs work through the same command, which is useful during development:

dsh plugin --profile desktop add ./dsh-approval-explainer

Development

lib/index.js        host half
lib/client.js       browser half
cordis.patch.yml    the bundle layer
package.json        package metadata and DSH declarations

Verification

This plugin was built alongside a suite of checks, most of which do not need DSH running:

node verify-evaluate.mjs      # real ESM evaluation — catches reference errors node --check misses
node verify-http.mjs          # drives a real HTTP server through all 8 routes
node verify-semantics.mjs     # dead code, contract consistency, risky patterns
node verify-client-boot.mjs   # browser-half load contract

Suites using vm.SourceTextModule need --experimental-vm-modules.

Prefer real evaluation over text matching. This plugin was once broken by calling fileURLToPath(import.meta.url) when the identifier was never imported: the call always threw ReferenceError, an outer catch swallowed it, and the function returned null forever. The text assertion source.includes('fileURLToPath(...)') passed, because those characters were in the file. A text assertion and a working function are separated by an entire scope resolution.

License

MIT