在 DSH Web 对话里把 mermaid 代码块渲染成图:每个代码块头部有切换按钮,可在图与源码之间切换;仍在流式输出的块保持源码,等消息结束后再渲染;首次显示图时才懒加载 mermaid;终端 UI 不受影响。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:jakehemmerle/dsh-mermaid
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
A DeepSeek Harness (DSH) web GUI plugin that renders ```mermaid code fences in chat messages as diagrams.
- Settled mermaid fences show the diagram inside the stock code-block card. A toggle button in the card header ("Show code" / "Show diagram") switches between the diagram and its source. The Copy button still copies the source.
- Fences that are still streaming stay as plain code until the message settles.
- Diagrams re-render when DSH switches between light and dark (
document.documentElement.style.colorScheme). - If a diagram has a syntax error, the code stays visible with a muted
Mermaid: <error>line under it. - mermaid (v12,
securityLevel: 'strict') lives in a lazy chunk,lib/client.mermaid.js, so it loads only after the first mermaid fence appears. Page boot loads only the smalllib/client.js.
Install
The package is a DSH bundle: package.json declares dsh.bundle.patch (./cordis.patch.yml, which inserts the ui-mermaid row) and dsh.client (the web half). Install it into a web profile with dsh plugin add, then restart dsh web:
# prebuilt tarball from a GitHub release (no build step)
dsh plugin --profile web add https://github.com/jakehemmerle/dsh-mermaid/releases/download/v0.1.0-rc.1/dsh-mermaid-0.1.0-rc.1.tgz
# or a local checkout, after building it
pnpm install && pnpm build
dsh plugin --profile web add link:/path/to/dsh-mermaid
dsh plugin add records the package as a profile dependency and appends it to dsh.profile.bundles; dsh --profile web --dump-config then shows one id: ui-mermaid row with name: dsh-mermaid. Remove it with dsh plugin --profile web remove dsh-mermaid.
Without the bundle, add the row to the profile patch yourself (for example ~/.dsh/profiles/web/cordis.patch.yml; this is how nix-config installs it). The name must then be the absolute path to the Node entry file; a directory path fails with ERR_UNSUPPORTED_DIR_IMPORT. Use one way or the other, not both, or the profile composes two ui-mermaid rows.
- insert:
- id: ui-mermaid
name: /path/to/dsh-mermaid/lib/index.js
Disabling the plugin removes its observers, injected nodes, <style> element and data attributes.
How it detects mermaid fences
DSH renders every fence through a React CodeBlock component with root div.md-code-block. For mermaid the visible label is the generic "Code block", so the language is not in the DOM. The plugin reads it from React's fiber props instead: it takes the element's __reactFiber$… fiber, walks up at most 4 levels, and uses the first memoizedProps that has string code and lang fields (src/fiber.ts). The same props carry streaming. When a message settles, the DOM may not change at all, so a MutationObserver can miss it. While any mermaid block is still streaming, the plugin also rescans every 500 ms.
A DOM node keeps the fiber it was created with. After every other commit, that fiber is the stale alternate. So the plugin reads the props chain of both the fiber and its alternate. It keeps the props whose code matches the text React rendered into [data-code-block-content] code, and if both match, it prefers the settled one.
The per-block logic is a pure state machine in src/fence.ts. Its states are waiting, rendering, rendered and failed. It is idempotent per (code, theme), and it drops stale render completions.
Development
pnpm build # esbuild -> lib/client.js + lib/client.mermaid.js (module-loader wrapped CJS)
pnpm typecheck
pnpm test # all tests
pnpm test:unit # fast-check properties of the pure core
pnpm test:e2e # real clients: shipped bundles in Chromium + Playwright campaigns on real `dsh web` + dsh-TUI inertness
The real-client suites run against a real dsh web and a real dsh-TUI on the vendored rig (test/rig/): every run gets its own private HOME/DSH_HOME, free port and private tmux socket, and the only model is the local mock (test/rig/mock-llm.mjs). Nothing reads a live ~/.dsh or ~/.dsh-tui; set DSH_BIN, DSH_ROOT, DSH_TUI_DIR and PLAYWRIGHT_BROWSERS_PATH to pinned store builds (see flake.nix's devShell) and run the suites via nix develop. MMD_INSTALL picks how the web and TUI suites install the plugin (test/install.ts): row (default, an explicit lib/index.js row as nix-config writes it), link (dsh plugin add link:<checkout>) or tarball (dsh plugin add of the pnpm pack output).
test/web/bundle-install.e2e.test.ts—dsh plugin addof the checkout and of the packed tarball: one composedui-mermaidrow, one bundle entry (also after a repeated add), and a rendered, visible diagram whose arrowhead resolves.test/web/mermaid.web.property.test.ts— fast-check generated action sequences (send / held send / toggle / theme / reload) against the real web client, invariants checked after every step; replay withNUM_RUNS,FC_SEED,FC_PATH.test/web/streaming.e2e.test.ts— paced-chunk streaming: the fence stays plain code while the turn streams, then renders once after settle; printsRELEASE_TO_DIAGRAM_MS=….test/web/duplicate-ids.test.ts— two identical fences get distinct SVG element ids.test/render.property.test.ts,test/client.dispose.test.ts— the shipped lazy chunk and browser bundle in headless Chromium (render properties incl. hostile labels; dispose restores the DOM and stops reacting).test/tui/mermaid.tui.inertness.test.ts— the plugin is web-only; on a real dsh-TUI the row composes, loads without warnings and full turns render byte-identically to a TUI without the plugin.test/contract/dsh-seam.contract.test.ts— pins the DSH seams (CodeBlock props, banner, fiber keying, module loader) against the exactDSH_ROOTbuild.
Suites write screenshots to test/artifacts/ on failure.
Nix
The flake builds the plugin for x86_64-linux, aarch64-linux and aarch64-darwin. packages.<system>.default contains lib/, package.json and cordis.patch.yml. Its build runs tsc --noEmit and the unit vitest project, and checks.<system>.default is the same package.
nix build github:jakehemmerle/dsh-mermaid # result/lib/index.js
nix flake check -L
As a flake input, use ${dsh-mermaid.packages.${system}.default}/lib/index.js as the name in the profile patch row above. After a pnpm-lock.yaml change, update hash in nix/package.nix with the value Nix reports.
CI (.github/workflows/nix.yml) runs nix flake check -L on Linux and macOS runners, so the package build with its tsc + unit checks and the DSH-seam contract check is exercised on both OSes. The real-client web/TUI suites need the pinned dsh web, dsh-TUI and Nix Chromium of the flake devShell, so they run locally or in the repo environment (nix run .#e2e).
Limitations
- The plugin depends on DSH
CodeBlockinternals: the.md-code-block,[data-code-block-banner]and[data-code-block-content]hooks, and the React fiber props{ code, lang, streaming }. If DSH changes them, the plugin finds no fences and you see the stock code block. Nothing breaks. - The diagram replaces the code view only visually. React still owns and renders the code block. The plugin adds a single container as the last child of the card and a single button in the header actions.
lib/client.mermaid.jsis about 5 MB (about 1.5 MB gzipped), because the full mermaid build is bundled, including elk/cytoscape/katex. It loads once, on demand.
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-task-board★ 9925
侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。
zhu1090093659/dsh-web#packages/dsh-web-all★ 9925
DSH Web UI 插件与皮肤合集:任务看板、git 图、右侧面板、远程移动端 UI、桌宠、实时 token 统计与皮肤中心。
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 6712
右下角常驻的小鲸鱼挂件:余额、今日已用与每轮对话消耗(含峰谷价),余额预警与今日预算的泡泡内容都可编辑;泡泡点击序列模块化自定义,支持并列加权 A/B、随机台词与随机图片;内置 30+ 厂商模板(OpenAI / OpenRouter / Kimi / 硅基流动 / 方舟 / 智谱 / MiniMax 等),按模型查余额与订阅额度;另有任务结束音效、导入音频、自定义角色与资源管理。数据全在本机,无遥测。
ccch1mneyyy/dsh-TUI★ 6538
Claude Code 风格全屏终端 UI:像素鲸鱼顶栏、实时工作状态行、思考流式展开。
omdsh-dev/DSH-better-sidebar★ 4808
侧边栏完整工作台:内置文件渲染编辑、终端、Git 与子代理,支持三方插件注册新 Tab。
Devin-AXIS/deepseek-design#deepseek-idesign★ 1672
可视化设计工作室,支持网站、App 原型、海报、信息卡、报告和杂志的模板创建、元素编辑、选区级 AI 草稿衔接与导出。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。