DeepSeek Harness Plugin Hub

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

探索

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

社区

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

相关链接

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

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

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
H

dsh-hint-shell

Hint Shell

DeepSeek Harness 的 Composer Shell 命令提示:在编辑器为空时的占位符后追加“输入 ! 以执行 Shell 命令”,并在输入 ! 后显示灰色提示。

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

npx -y @deepseek-ai/dsh plugin --profile web add github:Mooling0602/dsh-hint-shell#82a962bb6cd35bc905bd180251a5662315446dd3
README兼容性版本

兼容性与来源证明

Hint Shell 以 dsh-hint-shell 发布,当前版本为 0.1.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

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

版本

0.1.0stable
2026/10/23

相关插件

正在加载相关插件…

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

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

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

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

认领这个 Plugin →
报告问题

相关插件

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

Plugin Wallpaper Enginedsh-plugin-wallpaper-engineDSH web GUI 的 Wallpaper Engine 背景:将本地 Wallpaper Engine 壁纸渲染到聊天背景中——通过内置的 WebWallGL 引擎实时渲染 Scene 和 Web,直接播放 Video——配备 iOS 风格的液态玻璃效果,可调节模糊/遮罩/bClaude Designdsh-claude-designDeepSeek Harness 插件:来自 baoyu-design 的 claude-design 技能。智能体将画板画布写入文件,并在本地画布编辑器中打开它们。Claude Slidesdsh-claude-slidesDeepSeek Harness 插件:来自 baoyu-design 的 claude-slides 技能。代理会将可编辑的幻灯片演示文稿写入文件,并在本地幻灯片编辑器中打开。Genui@changfenhuang/dsh-genuiDeepSeek Harness 的 GenUI:通过 ```dsh-ui``` 代码围栏在助手回复中内嵌渲染交互式 UI 组件——布局、图表、绘图、表单、测验、mermaid、3D 场景,以及回传给模型的操作事件循环。随附用于教授代码围栏的主机插件

README

dsh-hint-shell

A DeepSeek Harness plugin that makes ! a shell prefix in the composer.

  • Empty composer — appends ,输入 ! 执行 shell 命令 to the shipped placeholder, so it reads 发消息或创建任务, / 调用指令, @ 文件或对话,输入 ! 执行 shell 命令.
  • After typing ! — shows a gray hint 输入 shell 命令… right after the !.
  • On submit — a line like !ls runs as a real shell command in the session's working directory. Its output is recorded in the session as a tool call and result, so the next real request already sees it. No model request is made for the ! line itself.

Nothing else changes: no new button, no replaced component, no altered keyboard behaviour.

! follows the same convention as /

The Harness treats a trigger symbol as a trigger only once something follows it: parseCommand requires at least one name character after /, and the composer's matchEnter bails when the token is empty. A lone / is therefore ordinary text, not a command.

! behaves the same way. A lone ! is prose and is sent to the model like any other message; only ! with a command behind it is shell intent. Both !ls and ! ls mean ls.

How it works

The composer effects reuse machinery the shipped composer already has.

Idle hint — the empty-composer placeholder is produced by a locale lookup of conversation/placeholder.default. LocaleRuntime.prototype.translate is a prototype method, so the plugin wraps it and appends one clause to that key (and to placeholder.hero, the same composer in its empty-session layout). Every other namespace and key passes through untouched.

Armed hint — the shipped stylesheet already paints this exact kind of message:

.input p:last-child::after {
  content: var(--dsh-composer-hint);
  color: var(--dsw-alias-label-caption);
}

Upstream only populates that property for a native command claim, which a ! prefix cannot produce. Custom properties inherit, so setting --dsh-composer-hint on the composer card is enough: the shipped rule then draws the text immediately after the typed !, in the shipped caption colour. The plugin adds no DOM, does no measurement, and does no positioning.

The draft itself comes from [data-composer-input], the editable surface the composer already publishes, so this plugin has no companion plugin and no dependency on internal trigger internals.

Copy

Copy lives in the plugin's own dsh-hint-shell locale namespace, so registration can never collide. The locale service's register is append-only and throws on a duplicate (namespace, locale) pair, which is why overriding the conversation namespace from a plugin is not possible.

zhen
idle clause,输入 ! 执行 shell 命令, type ! for shell commands
armed hint输入 shell 命令…Enter a shell command…

Edit src/copy.ts to change them.

Execution

The host half hooks agent/pre-step, the last point before the loop dispatches a request, and its reject decision stops that request. A ! line therefore costs zero tokens.

Recording the outcome needs a whole tool exchange, not one event. The model-visible surface carries tool/result but not tool/call, and a tool result with no preceding assistant tool-call block is a message answering a call that was never made — which a provider rejects. The records are written the way the agent loop writes its own, and in the shape the session's format v4 reader validates when the session is reopened:

  1. step/start — agent/pre-step runs before the loop opens its step, and v4 requires every surface message to belong to an open step. The plugin opens one for the pair.
  2. system/message with empty content — only when the surface is still empty. V4 protects the first system message as the surface head, and a later system/message cannot be appended without one. A ! line can be the first thing a session ever does, so the head is reserved; empty content derives to no model message and renders no transcript row.
  3. assistant/message carrying the tool-call block (surface event, identified message)
  4. tool/call (log-only, for the UI and replay)
  5. tool/result (surface event: an identified tool-role message whose source.callId matches its toolCallId, citing the tool/call seq as its source event)
  6. step/end — closes the synthetic step so the loop's turn/end stays legal

Every message carries a fresh UUID id and a producer-owned source.kind, which is what the v4 reader checks on reopen. Omitting any of this is not a cosmetic problem: the live append succeeds, then the persistence encoder refuses the row, the buffered batch never reaches the log, and the turn fails with a format error such as format v4 tool/result at seq 8 requires a first-class message with a string id.

Because these are appends to the durable log and the step was rejected, the command's output sits in the history for the next request without one being made for it.

Commands run through /bin/sh -c, so quoting, pipes, and globs behave as in a terminal rather than being re-implemented. Output is capped at 30 000 characters, and a non-zero exit or a signal is reported as a tool error.

subprocess is read optionally rather than declared in inject: a hard dependency would make Cordis refuse to mount the whole plugin when no provider is composed, taking the composer hints down with it. Without a provider the hints still work and a ! line records a tool error naming the missing service.

Development

Sources are TypeScript; both shipped JavaScript files are generated.

npm install          # typescript + esbuild + @types/node
npm run typecheck    # tsc --noEmit
npm run build        # src/ -> client.js, host.ts -> index.js
npm test             # composer, shell-line, and installed-Harness format tests

test/dsh-format.test.ts drives the host hook against an installed Harness: it appends through a real Session, then encodes, admits, and restores the log through the real format v4 reader, so a record shape the live app accepts but cannot re-open fails the suite. It resolves the harness packages from the host installation (DSH_MODULES, or the global npm root -g) and reports a skip when none is installed.

client.js must stay a single self-contained file: the Client module loader's require resolves host packages only and cannot resolve relative imports, which is why the build bundles src/ rather than shipping it. index.js is built rather than shipping .ts so the host never depends on the runtime having TypeScript stripping enabled.

Layout

PathPurpose
host.tsHost half: the ! pre-step hook (source).
index.jsGenerated Host module. Do not edit.
client.jsGenerated Client bundle. Do not edit.
src/copy.tsThe two strings, in both languages.
src/index.tsThe two composer effects: placeholder clause and hint painting.
src/exec.tsShell-line parsing, execution, and output formatting.
src/types.tsStructural types for the Client services used.
src/host-types.tsStructural types for the Host services used.
test/run.test.tsComposer integration test (fake DOM + fake locale).
test/host.test.tsShell-line and pre-step hook test.
test/dsh-format.test.tsInstalled-Harness test: append through a real Session, then reopen the log through the real v4 reader.
cordis.patch.ymlProfile bundle row.

Behaviour notes

  • The hint shows only while the draft is the bare !; typing a command clears it. No space is needed after the !.
  • The hint never shows on an empty composer (the placeholder covers that case) or in the middle of a sentence (hello !world is ordinary text).
  • The hint follows the active locale; switching language re-renders it.
  • Uninstalling restores the original translate.

Why a MutationObserver is involved

The editable surface belongs to Lexical, which commits typed text into its own paragraph nodes inside its update pass. That pass is not guaranteed to finish before the browser dispatches input, so a synchronous read of [data-composer-input] can still describe the previous character. Reading only on input made a bare ! appear one keystroke late — it showed up after the space that followed, and then appeared to "stick" when the draft was deleted back to !.

The plugin therefore repaints on the mutation Lexical actually makes, which is the authoritative signal that the text is in the DOM. A deferred read on input remains as a safety net. Both paths only schedule a paint, so an extra paint is cheap and idempotent.