DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

dangxinxing090-svg /

dangxinxing090-svg/dsh-plugin-plain-slides

Verified

A DeepSeek Harness plugin that turns each agent reply into a short slide deck in plain language — for people who use the harness but do not read code.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@5466b48c

brief

A DeepSeek Harness plugin that turns each agent reply into a brief: a few slides, conclusion first. For people who use the harness but do not read code.

The agent still writes whatever it writes. This plugin gives you a second way to read it: every reply is re-shown as a few slides — conclusion first, then a few steps, then any question the agent is waiting on you to answer. The original text is always one click away, and the plainly-worded version is one press away, on the turns you want it.


What it solves

An agent finishes a task and prints a wall of text: file names, code, jargon, parentheses, paths. If you read code, you scan it and know what happened. If you do not, you finish it and still do not know whether it worked.

This plugin puts a slide deck where that reply would have been — a few pages, not a wall:

Slide Content What it is for
1 Conclusion Read this one page and you know the result
2–6 Process What actually happened, one line per step
last Questions If the agent needs a decision, click an option or type a reply

Nothing is deleted. The 完整原文 button in the card header switches to the full original text, with a technical summary line (elapsed time, operation count, token usage) above it, and switches back with 回到幻灯片.


Install

On a machine with DeepSeek Harness (dsh) installed:

dsh plugin --profile web add github:dangxinxing090-svg/dsh-plugin-brief

This installs straight from this repository, and it works today — the package is not on npm yet.

Once it is published to npm, the shorter name resolves too:

dsh plugin --profile web add dsh-plugin-brief

Restart dsh. That is the whole install — the package mounts itself, so there is no config file to edit.

Replace web with your profile name (tui is the other common one). To pin a release instead of tracking the default branch, append a tag or commit: github:dangxinxing090-svg/dsh-plugin-brief#v0.1.0.

Manual install
  1. Install the package in the profile directory:

    cd ~/.dsh/profiles/web
    pnpm add github:dangxinxing090-svg/dsh-plugin-brief
    
  2. Append to cordis.patch.yml in the same directory:

    - insert:
        - id: brief
          name: 'dsh-plugin-brief'
    
  3. Restart dsh. dsh --dump-config prints the composed tree if you want to confirm the row first.

Edit cordis.patch.yml, never cordis.yml — the latter is generated.

Uninstall

dsh plugin --profile web remove dsh-plugin-brief

Publishing your own copy

Forking this and publishing under your own name? Three things must stay consistent:

  1. name in package.json — your published package name.
  2. The name: inside cordis.patch.yml — that is the row's module specifier, and it must equal the package name, or the loader cannot resolve the row.
  3. The copyright line in LICENSE.

The row id (brief) is only a composition key; rename it freely.


Rewriting is something you ask for

A reply costs nothing by default. The card opens on · 原版 — the same slides laid out locally from the agent's own words, correct layout and unprocessed wording — with a 通俗化 button beside the flag.

Press it, and the header reads · 通俗化中… while that turn's rewrite is in flight. Then either:

  • · 通俗版 appears — the rewrite succeeded, and you are reading plain language; or
  • the flag goes back to · 原版 — the rewrite failed, and you keep the locally rendered version. Still correctly formatted, just not simplified.

The local deck never blanks the card and never shows broken markup.

A success is kept. Come back to that turn — after a reload, or after restarting DSH — and pressing 通俗化 shows the plain version straight away: no · 通俗化中…, and no second call to your model, ever.

Once a plain deck exists the card holds both wordings, and the button beside the flag moves between them: 原版 while you are reading the plain version, 通俗化 to go back to it. That switch is a separate control from 完整原文, which leaves the deck for the full markdown.


What the conversation itself shows

The card is only half of it. The plugin also tidies the transcript around it, so you are not scrolling past the agent's homework to find the answer:

In the transcript What you see
While a turn is running a two-line box just above the composer, under the 深度求索中... status — a title naming what is happening and pointing at the Trajectory, then the latest step in plain language. Close it and it stays closed; a labelled switch in the session header (显示工作过程 / 隐藏工作过程) toggles it in any state
When the turn settles your message, then the deck
Tool rows, reasoning, tool folds, injected context, compaction markers, retries, the system prompt nothing at all
Failures and truncation (turn-error, turn-max-tokens) kept — you always learn when something went wrong
Approvals, questions, plan review, presented files kept — each renders outside the tool row (the composer, the turn footer, the sidebar plugin panel)
A dynamic plugin's own inline UI (tool.view.cordis) hidden with its row — the one real loss
Everything hidden above still in the Trajectory view, one click away

Nothing is deleted. The plugin changes what is shown by default, not what is recorded.


Cost

Nothing by default. A reply is laid out locally at no cost, and a model call happens only when you press 通俗化 on a turn.

  • It uses your currently selected default model.
  • Only the turn's report is translated. The working process is never sent.
  • A success costs exactly one call, and is kept — asking again for the same turn, in this session or a later one, shows the plain version without asking the model a second time, ever.
  • A failure is retried at most three times, so one ask costs at most four calls, and each retry gets a wider output budget than the first attempt. The button comes back afterwards, so a failed ask can be repeated — that is a new ask, not a silent one.
  • Scrolling back never re-requests.
  • To remove the rewrite entirely — button included — add disabled: true to the plugin row.

How it works

Four parts:

  1. It takes over the reply renderer. The plugin registers into the harness's assistant-message seat, so the raw markdown is no longer rendered directly — the slide card is.
  2. It takes over the working-process renderers. The same seat is keyed by message kind, so the plugin claims tool rows, reasoning folds, injected context, compaction markers, retries and the system prompt, and renders them as nothing — from the turn's first second, without waiting for the harness's own process fold. That fold only engages for a closed turn that produced a final answer, which is precisely not while a turn runs, nor after one is aborted. The plugin also collapses those rows itself rather than trusting the harness's :empty rule: every one of them keeps a child element, so the rule never fires and each row would still take the column's 16px sibling margin — thousands of pixels of blank in a single turn. The working box is not a renderer at all but a composer dock entry, because only the dock draws after the conversation and therefore after the status label. Interactive seats cannot be claimed this way, so the plugin verifies their homes instead: approvals and questions in the composer, deliverables in the turn footer, dynamic-plugin approve/decline in the sidebar panel.
  3. The rewrite is opt-in, and it is the report only. A reply is laid out locally first, so a turn costs nothing until you press 通俗化 on it. That press sends the closing step's text — never the process — to your model with a strict instruction: emit HTML fragments in a fixed line protocol, one conclusion and a few steps. One success ends that turn's budget and is kept; a failure is retried at most three times; and the rewrites are serialised, so a burst cannot start.
  4. The local rendering is the default, not a fallback. The client splits the original text itself with a small markdown → HTML converter. That is what you read unless you ask for the rewrite, and what you keep reading if the rewrite fails. Correct layout, unprocessed wording.

The client half talks to its host half over Connection's authenticated /api fetch channel (ctx.connection.fetch.register), so the harness applies its Host/Origin trust fence and browser-session cookie before the handler runs. The plugin implements no authentication of its own.

Model output is sanitized before rendering: only a small allow-list of bare text tags survives, every attribute is stripped, and <script>-like elements are removed whole.


FAQ

A slide is filler, like "plugin updated". The plugin already filters status-only and near-empty pages, and the rewrite prompt tells the model not to emit them. If one slips through, open an issue with that slide's text.

A table renders as a row of pipes. That turn did not go through the HTML path. Open an issue with the full reply.

I want the agent to answer plainly in the first place, not be translated afterwards. That is a different change — it belongs in the agent's prompt, not this plugin. This plugin deliberately leaves the agent's own words alone, because those words are also what it uses to keep working.

The reply was long. Did I lose content? The deck shows at most one conclusion slide plus five process slides. Everything else is in the full-original view.

Does this send my data anywhere? No. The rewrite uses the same model service your conversation already uses. This plugin has no network access of its own and collects nothing.


Troubleshooting

The card never appears, and startup reports a plugin load failure.

Every registration into conversation.chat.node went in at the default slot priority, while the harness's own renderer already owned those same keys at that same priority. Two registrations competing for one cell at one priority is not a tie the slot system resolves: the row fails to load and the plugin contributes nothing. That was the v0.1.0 bug — the plugin never mounted on any harness.

Fixed in v0.1.1: every registration now carries priority: -10, which wins the cell. On v0.1.0, upgrade.

Is the plugin loaded at all? A loaded plugin renders every reply as a card with a 演示 button on it. If replies are plain markdown, it is not loaded — and the harness itself is fine; the failure is confined to this plugin's own row.

The card renders but the wording is still technical. That is the default: a reply is laid out locally and nothing is rewritten until you press 通俗化 on it. If you pressed it and the flag went back to · 原版, the rewrite failed — open the browser console and look for brief:, which reports how many attempts it made and why the last one produced nothing.


Development

No build step — the files in lib/ are the source.

lib/index.js       host half: one rewrite call per request, and the /api route
lib/client.js      browser half: reply renderer, slide deck, local deck builder
cordis.patch.yml   the self-mounting bundle patch
test/              runnable verification for both halves
npm test

test/host.test.mjs mounts the host half against a fake context and drives the real route with Request/Response objects. test/client.test.mjs drives the actual browser-bundle contract: it captures the window.__ModuleLoader__ registration, calls the factory with a stub require, and asserts every contribution the client half makes — the five seats it registers into, the kinds it takes over, the rewrite's call budget and kept decks, and the working box.

To try a local checkout without publishing:

dsh plugin --profile web add /path/to/dsh-plugin-brief

Shadowing a built-in slot

conversation.chat.node is a keyed slot whose keys the harness already owns. A permanent client plugin that registers one of those keys at the default priority does not merely lose to the shipped renderer — the plugin fails to load and contributes nothing, with a load error at startup. Always declare a shadowing priority:

slots.register({ name: 'conversation.chat.node', key: 'assistant-step', priority: -10 }, View)

A lower number wins the cell. test/client.test.mjs enforces this across every conversation.chat.node registration, so adding a key and forgetting the priority fails the suite before release. List slots (conversation.chat.assistant-actions, shell.overlay) are additive and need no priority — give them an id of your own instead.

MIT licensed.



brief(中文)

一个 DeepSeek Harness 插件。把每一轮 AI 的回答变成一份简报:几页幻灯片,先给结论。给用这个 harness、但不读代码的人。

AI 该怎么写还是怎么写。这个插件只是给你第二种读法:每轮回答都被重新呈现成几页幻灯片——先给结论,再列几步过程,最后是 AI 在等你拍板的问题。原文永远只差一次点击,大白话版本则在你想要的那几轮上差一次按下。


它解决什么问题

AI 干完活,吐出一大段文字:文件名、代码、术语、括号、路径。懂代码的人扫一眼就知道发生了什么;不懂的人读完了,还是不知道到底成没成。

这个插件在原本那段回答的位置放一副幻灯片——只有几页,不是一堵墙:

页 内容 作用
第 1 页 结论 只读这一页就知道结果
第 2–6 页 过程 每一步实际做了一件什么事
最后几页 问题 如果 AI 在等你决定,点选项或直接输入回复

什么都没删。卡片右上角的 完整原文 按钮随时切回完整原文,原文上方还有一行技术统计(耗时、操作次数、token 用量);进入原文后按钮变成 回到幻灯片。


安装

在装了 DeepSeek Harness(dsh)的机器上执行:

dsh plugin --profile web add github:dangxinxing090-svg/dsh-plugin-brief

这是直接从本仓库安装,现在就能用——这个包还没发布到 npm。

等它发布到 npm 之后,短名字也成立:

dsh plugin --profile web add dsh-plugin-brief

然后重启 dsh。安装就这一步——包会自己挂载自己,不需要改任何配置文件。

把 web 换成你实际用的 profile 名(另一个常见的是 tui)。想锁定某个版本而不是跟随默认分支,在末尾加上 tag 或 commit:github:dangxinxing090-svg/dsh-plugin-brief#v0.1.0。

手动安装
  1. 在 profile 目录里安装:

    cd ~/.dsh/profiles/web
    pnpm add github:dangxinxing090-svg/dsh-plugin-brief
    
  2. 在同目录的 cordis.patch.yml 里追加:

    - insert:
        - id: brief
          name: 'dsh-plugin-brief'
    
  3. 重启 dsh。想先确认的话,dsh --dump-config 会打印组合后的插件树。

要改的是 cordis.patch.yml,不要改 cordis.yml——后者是自动生成的。

卸载

dsh plugin --profile web remove dsh-plugin-brief

发布你自己的版本

想 fork 出去用自己的名字发布?三处必须保持一致:

  1. package.json 里的 name —— 你发布的包名
  2. cordis.patch.yml 里的 name: —— 这是插件行的模块标识符,必须等于包名,否则加载器找不到这一行
  3. LICENSE 里的版权行

行里的 id(brief)只是组合键,随便改。


通俗化是要你点才会做的

默认一分钱不花。 卡片打开时是 · 原版——同样的幻灯片,但由 agent 自己的原话在本地排版而成,排版正确、用词不加工——旁边有一个 通俗化 按钮。

按下去,卡头变成 · 通俗化中…,在等这一轮的改写返回。之后二选一:

  • 出现 · 通俗版 —— 改写成功,你读到的是大白话;或
  • 卡头退回 · 原版 —— 改写失败,你继续看本地渲染的版本。排版仍然正确,只是用词没加工。

本地排版不会让卡片空白,也不会显示破损的标记。

成功一次就会存下来。 以后回到那一轮——刷新页面也好、重开 DSH 也好——再按 通俗化 会直接显示通俗版:不会先出现 · 通俗化中…,也不会再问一次模型。

一旦通俗版存在,卡片同时持有两种措辞,标记旁边的按钮在它们之间切换:正在读通俗版时显示 原版,点它回到通俗版时显示 通俗化。这个开关和 完整原文 是两回事:后者会离开幻灯片、显示完整 markdown。


对话里还剩什么

卡片只是一半。插件同时会把对话本身整理干净,你不用翻过一堆"作业"才能看到答案:

对话里的位置 你会看到
一轮正在进行时 composer 上方一个两行框,位于「深度求索中...」下面 —— 第一行标题说明正在做什么并指向轨迹页,第二行是最近一步的普通话描述。关掉它就一直是关的;会话标题栏有一个带文字的开关(显示工作过程 / 隐藏工作过程),任何状态都能切换
一轮结束时 你的消息,然后是幻灯片
工具行、思考过程、工具折叠、注入的上下文、压缩标记、重试、系统提示 完全不显示
失败与截断(turn-error、turn-max-tokens) 保留 —— 出了问题一定会告诉你
授权、提问、计划确认、交付物 保留 —— 各自都有工具行之外的落点(composer、轮次页脚、侧栏插件面板)
动态插件自己的行内界面(tool.view.cordis) 随工具行一起隐藏 —— 这是唯一的真实代价
上面被隐藏的内容 都在"轨迹"视图里,点一下就能看

什么都没删。插件改变的是默认显示什么,不是记录什么。


花多少钱

默认不花钱。 回答先在本地排版,只有你按下某一轮的 通俗化 按钮,才会发生模型调用。

  • 用的是你当前选中的默认模型
  • 只翻译这一轮的结果,工作过程从不发给模型
  • 成功只调用一次,并且会存下来——以后对同一轮再按一次,无论在本次会话还是下次打开,都直接显示通俗版,不会再问模型
  • 失败最多重试三次,所以一次请求最多四次调用;每次重试的输出预算比首次更宽。失败后按钮会回来,可以再按——那是你主动发起的新一次请求,不是偷偷重试
  • 往回翻永远不会重新请求
  • 想彻底去掉改写(连按钮一起),在插件行上加 disabled: true

它是怎么工作的

四个部件:

  1. 接管回答的渲染位。 插件注册进 harness 的"助手消息渲染位",所以原始 markdown 不再直接渲染——由幻灯片卡取代。
  2. 接管工作过程的渲染位。 同一个渲染位是按消息种类分键的,插件把工具行、思考折叠、注入的上下文、压缩标记、重试和系统提示全部认领下来,渲染成空——从一轮的第一秒就生效,不等 harness 自带的过程折叠(那个折叠只在"轮次已关闭且有最终答复"时才启用,恰好在一轮进行中和任务中止后是关着的,而那两个时刻正是过程最不该刷屏的时候)。此外插件自己把这些行收起来,不依赖 harness 的 :empty 规则:实测每个被隐藏的节点里都留着一个子元素,那条规则从不生效,于是每一行照样吃掉转录列的 16px 相邻外边距——一轮下来就是几千像素的纯空白。工作框本身不是渲染位,而是一个 composer 停靠项,因为只有停靠层绘制在整段对话之后,也就是绘制在「深度求索中...」之后。承担交互的渲染位不能这样认领,所以插件改为确认它们的落点在别处:授权与提问在 composer,交付物在轮次页脚,动态插件的批准/拒绝在侧栏面板。
  3. 通俗化是 opt-in,而且只改写结果。 回答先在本地排好版,所以在你按下某一轮的 通俗化 之前,这一轮不产生任何调用。按下之后,插件才把收尾那一步的文字交给你的模型(过程永远不发),要求严格按固定行协议输出 HTML 片段:一句结论、若干步过程。成功一次就结束这一轮预算并永久留用;失败最多重试三次;改写之间是串行的,不会一次涌出一批调用。
  4. 本地渲染是默认路径,不是兜底。 客户端自己用一个小型 markdown → HTML 转换器把原文切排。除非你按了通俗化,你读到的就是它;改写失败时你继续读的也是它。排版正确,用词不加工。

浏览器半边通过 Connection 的带鉴权 /api 通道(ctx.connection.fetch.register)和宿主半边通信,所以 Host/Origin 信任栅栏和浏览器会话 cookie 由 harness 在处理函数运行前统一校验,插件自己不做任何鉴权。

模型返回的 HTML 在渲染前会过白名单过滤器:只放行少数几个裸文本标签,所有属性一律剥掉,<script> 之类整段删除。


常见问题

有一页是废话,比如"插件已更新"。 插件已经会过滤只有状态、没有内容的页,改写提示词里也明令禁止。如果还漏了,把那一页的文字贴上来开个 issue。

表格显示成一堆竖线。 那一轮没走通 HTML 路径。请附上完整回答内容开 issue。

我想让 AI 一开始就用大白话回答,而不是事后翻译。 那是另一件事——属于 agent 的提示词,不属于这个插件。这个插件刻意不改 AI 的原话,因为那些话它自己还要拿来继续干活。

回答很长,内容丢了吗? 幻灯片最多显示 1 页结论 + 5 页过程。剩下的都在"完整原文"里。

它会把我的数据发到别处吗? 不会。改写用的就是你本来就在用的那个模型服务。这个插件自己不联网、不收集任何东西。


排错

卡片一直不出现,启动时报插件加载失败。

插件注册 conversation.chat.node 时用的是默认优先级,而 harness 自带的渲染器早就占了同样的 key、同样的优先级。同一个格子里两个注册抢位,不是"谁赢"的问题 —— 整条 row 加载失败,插件什么都没贡献。这就是 v0.1.0 的 bug:它在任何 harness 上都装不上。

v0.1.1 已修复:每个注册都带 priority: -10,数字更低,赢得格子。你如果装的是 v0.1.0,请升级。

怎么判断插件到底有没有加载? 加载成功时,每条回复都是一张卡片,右上角还有一个"演示"按钮。如果回复是普通 markdown,就是没加载 —— 但 harness 本身没事,失败只局限在这个插件自己那条 row 里。

卡片出来了,但用词还是很专业。 这是默认状态:回答先在本地排版,你没按 通俗化 就不会改写。如果你按了、卡头又退回 · 原版,说明改写失败——打开浏览器控制台找 brief:,它会报告尝试了几次、以及最后一次为什么没产出内容。


开发

没有构建步骤——lib/ 里的文件就是源码。

lib/index.js      宿主半边:每次请求恰好一次改写调用,以及 /api 路由
lib/client.js     浏览器半边:接管回答显示、渲染幻灯片、本地排版
cordis.patch.yml  自挂载补丁
test/             两个半边各自的可运行验证
npm test

test/host.test.mjs 把假上下文挂上宿主半边,用真正的 Request/Response 打通整条路由;test/client.test.mjs 验证真实的浏览器包契约——捕获 window.__ModuleLoader__ 注册、用桩 require 调用工厂函数,并断言客户端半边的每一项贡献:它注册的五个槽位、接管的节点种类、改写的调用预算与留存的通俗版、以及工作框。

想试本地 checkout 而不发布:

dsh plugin --profile web add /path/to/dsh-plugin-brief

覆盖 harness 自带的槽位时,必须给优先级

conversation.chat.node 是按 key 分格的槽位,而这些 key 早就被 harness 占着。永久客户端插件用默认优先级注册同一个 key,不是"输给"自带渲染器 —— 是整个插件加载失败、什么都没贡献,启动时还会报一个加载错误。必须显式声明一个能赢的优先级:

slots.register({ name: 'conversation.chat.node', key: 'assistant-step', priority: -10 }, View)

数字更低者赢得格子。test/client.test.mjs 对每一个 conversation.chat.node 注册都强制检查这一点 —— 以后加了新 key 却忘了优先级,测试会在发布前就失败。列表型槽位(conversation.chat.assistant-actions、shell.overlay)是可叠加的,不需要优先级,但要用自己的 id。

MIT 许可。

—/ 5

No ratings yet

Verified DSH bundle

Commit 5466b48c9b01

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