先生点名审计一键安装链,发现三处会让其他用户踩坑的疏漏: - install-v6.cjs: case"html" 目标形态落后(v6.0 ==='1') → 升级 v6.35 三态化(!=='0' + 回退诊断),新老前端两套同步;补 case"code" 围栏兜底状态机(RAW/V1/V2 → V3),新版未知形态 警告跳过不阻塞 - install-v6.cjs: 幂等分支升级为增量加固——已打旧 v6.0 老逻辑的 用户跑本脚本自动升三态化+补围栏兜底(备份+node --check+回滚) - trusted-patch.cjs: 只支持老版 vc(i.localName) → 补新版 Xu(l.localName) 锚点组 + 代际探测 + 双幂等 + 双语法预检 - install-all.cjs: 加 update-v6-inject.cjs 步骤(旧 v6 渲染模块升级) 验证:老 v6 模拟加固通过、新老双锚点模拟全过、install-all 三步幂等干跑 exit 0、全套回归 315 断言全绿
dsh-raw-html · VCP Visual-Synesthesia Protocol Plugin
Brings VCP (Visual-Synesthesia) to the DeepSeek Harness Web GUI: HTML in messages goes from "a blob of source code" to a genuinely rendered interface, and the agent outputs following a maintainable design system.
Plug & play: any computer, any agent — run the one-shot installer patch (node patch/install-all.cjs, rendering capability + Trusted Mode in one command)
- install this plugin + toggle the 「</>」switch in the browser → the browser renders HTML (including SVG cards / Mermaid charts / KaTeX math), the agent follows the design spec (design principles / Chinese typography / font pairing).
The rendering capability (HTML/SVG/charts/math) is injected into the frontend bundle by the patch; the plugin provides the toggles and the protocol injection — see the Install section below.
✨ Gallery
VCP cards rendered in real conversations (5 promo banners):
📣 What's New (v0.3.0 · patch v6.18)
2026-08-24 updates
- Fixed (frontend compatibility):
install-v6.cjsnow supports dsh-web-frontend 0.1.0-rc.8 / 0.1.1-rc.x (bundleindex-CA9Bpko5.js/index-ClqxG24t.js), where the minifier renamedvc→Xuandhp→jd/Sd. A new anchor set with automatic generation detection was added; legacy anchors (rc.5~rc.7) are kept intact and regression-verified. - Fixed (startup crash): removed the static
@deepseek-ai/schemasteryimport fromlib/index.js— the only third-party runtime dependency. It is now loaded dynamically with a graceful fallback, so the plugin boots fine even whennode_modulesis missing (static import chain is now built-in Node modules only). - Feature: declarative color presets — write
data-vcp-preset="editorial|chiaroscuro|fauvism|cyberpunk|wabi_sabi"and the built-in VCPColorEngine deterministically generates the whole--vcp-*palette (WCAG contrast & sRGB gamut closed-loop; hex never passes through the LLM; stable across streaming rebuilds). - Feature: streaming anchor lock (CSS-only
overflow-anchorlock) + cached ref closures — smoother streaming, no per-framesetPropertystorms. - Protocol: render/aesthetic split toggles; active visual-synesthesia prompting; flow discipline moved to the structural layer (measured output −4.6K tokens/turn, cost −¥0.056).
Audit hardening (2026-08-21)
- Security (P0): fixed the
on*attribute passthrough gap (only theonclickbridge is allowed); fixed the performance-timer diagnostics; aligned documentation references. - Performance (P1): fast guards for regex conversions, fixed the mermaid global-listener leak, protocol text slimmed by ~74%.
- Fonts (P2): 12 built-in commercial fonts → 7 open-source fonts (all OFL-licensed).
- Enhancements:
prefers-reduced-motionaccessibility, keyboard focus states, named constants for magic numbers. - See CHANGELOG.md for the full list.
Versioning
- Plugin version: the
versioninpackage.json(currently 0.3.0), upgraded viadsh plugin. - Patch codename: the evolution codename of the
patch/injected modules (currently v6 · sub-version v6.38), applied to the frontend bundle byinstall-all.cjs. The two evolve independently. Frontend compatibility: 0.0.1-rc.5 ~ 0.1.0-rc.7 and 0.1.0-rc.8 / 0.1.1-rc.x (thevc/hpandXu/jdminified shapes are auto-detected).
Components
| Component | Path | Purpose |
|---|---|---|
| One-shot installer | patch/install-all.cjs |
Recommended: one command = install-v6.cjs (rendering capability) + trusted-patch.cjs (Trusted Mode vc gating); idempotent + backup/rollback + node --check health check, aborts safely on anchor mismatch |
| Universal installer | patch/install-v6.cjs |
Rendering-capability full v6 patch (component ① of install-all): auto-detects the dist bundle and applies the full v6 patch from any historical state (idempotent + backup/rollback + node --check health check) |
| Trusted Mode vc patch | patch/trusted-patch.cjs |
Component ② of install-all: turns the hard script/iframe/object/embed filter in vc() into a conditional one gated by window.__vcpTrusted (off by default = safe) |
| Stable-state render module | patch/v6-inject.js |
Incremental render engine injected into the bundle: container-aware block caching, streaming-tail placeholders, KaTeX math, Mermaid viewer; onclick="input('...')" bridge for real interaction; filters script/iframe/object/embed, on* events and javascript: protocols |
| vcp-fast engine | patch/v6-inject.js |
Container-aware block-level incrementality: closed blocks cached (element references stay stable across frames → React skips diff → real looping animations), only the tail re-rendered; measured cache-hit 1200~6800×, incremental 12× speedup |
| Plugin (host side) | lib/index.js |
Toggle state (persisted to disk) + VCP protocol injected into the system prompt + /fonts font service (built-in + external library dual source) + shared knowledge (the protocol carries the local DESIGN.md path for any agent) |
| Plugin (browser side) | lib/client.js |
Injects the 「</>」toggle next to the composer send button + exposes window.__dshInput (VCP button → fill & send) |
| Built-in fonts | assets/fonts/ |
7 open-source fonts (woff2 subsets, ~7.6MB) shipped with the plugin — WenKai / WenKai Light / MaShanZheng / HeiTi / HeiTi Light / HeiTi Bold / GreatVibes, all OFL-licensed, zero config |
| Design system docs | DESIGN.md |
Full spec library: font list / palettes / Chinese typography / security iron laws (knowledge layer; agents may read on demand) |
| Regression tests | tests/ |
Six suites (stable 47 + security 43 + bundle + smoke + math + mermaid, 200+ assertions): frame sequences / security filtering / bundle integrity (run after any engine change) |
| Benchmark | patch/vcp-fast-bench.cjs |
Compares old/new paths in a real DOM parsing environment (auto-downloads dependencies, zero install) |
| Subset tool | tools/subset_fonts.py |
For maintainers: trims new fonts to common-character subsets + woff2 compression (needs Python + fonttools + brotli) |
Install (any DSH environment · for humans & agents alike)
Recommended: one-shot installer patch/install-all.cjs — one command installs everything
("rendering capability + Trusted Mode"; internally runs install-v6.cjs full render patch then
trusted-patch.cjs vc gating; idempotent, every step auto-backs-up + node --check health check,
aborts safely without writing on anchor mismatch):
# 1. One-shot patch (HTML rendering / SVG cards / Mermaid charts / KaTeX math / Trusted Mode — all in place)
node "path\to\plugin\patch\install-all.cjs"
# 2. Install the plugin (uninstall: dsh plugin --profile web remove dsh-raw-html)
dsh plugin --profile web add "path\to\plugin"
# 3. Restart the dsh service, then hard-refresh the browser (Ctrl+F5 if cached)
# 4. Toggle the 「</>」switch (render/aesthetic); click the bottom-right Trusted Mode badge for scripts
Agent install guide (for users letting their own agent install this plugin — hand these 4 steps to the agent as-is): ① verify Node.js is available (
node -v); ② run the one-shot installerinstall-all.cjs(auto-detects the dist bundle; pass<bundle-path>as an argument if detection fails); ③ register the plugin into the web profile; ④ tell the user to restart dsh and hard-refresh. All patches are idempotent — re-installing or re-running after a dsh upgrade has no side effects.
If auto-detection fails, specify the bundle path manually:
node "...\patch\install-all.cjs" "C:\...\dsh-web-frontend\dist\assets\index-*.js"
They may also be run individually:
install-v6.cjs(rendering) /trusted-patch.cjs(Trusted Mode vc gating); legacy scripts (v1/v2 era)patch/install.cjs,patch/patch-frontend.cjs,patch/upgrade-patch.cjsare kept in the source repo for reference; useinstall-all.cjsfor daily installs.
vcp-fast engine (v0.3.0)
The "cache + incremental" dual engine (window.__vcpFast) layered on the v1 render patch:
- Exact cache: when the HTML string is unchanged, returns the cached React element reference — React skips reconciliation for identical references. History scrolling / session switching / React re-renders → zero rebuild.
- Incremental append: content = old content + appended segment, and when the old content ends with a closed tag, stable parts keep their references and only the new segment is parsed.
- Safety boundary: only active in non-streaming mode with the toggle on; falls back to full re-render on unclosed old values or content rewrites; cache capped at 200 entries; onclick bridging and script/iframe filtering unchanged.
- Verify:
[vcp-fast] HIT/BUILDlogs in the DevTools console (throttled every 2s); benchmarks inpatch/vcp-fast-bench.cjs(measured in a real DOM environment:12006800× cache-hit, ~12× incremental speedup).
⚠️ Common pitfall: no blank lines inside vcp-root (important!)
A markdown HTML block ends at a blank line (\n\n) — if <div id="vcp-root"> contains two consecutive line breaks, the card is split into multiple nodes: the opening part is auto-completed by DOMParser into a small card with only a top background strip, and the rest overflows outside the background. Symptom: the dark background only wraps the top strip, and content below has no background (confirmed 2026-08-19).
Rules:
- All children inside vcp-root use single line breaks or stay on one line; never leave
\n\nanywhere; - Use
marginfor visual grouping, not blank lines; - After writing, check: the card HTML string must contain zero occurrences of
\n\n.
Config
- Built-in fonts (recommended): 7 open-source fonts shipped with the plugin (all OFL-licensed), zero config.
- External font library (optional): defaults to
I:\字体. PointSettings → Plugins → raw-html → fontsRootto your own library (or edit the default inlib/index.js). Works fine without one: 7 built-in open-source fonts + system fonts as fallback. - Toggle state: persisted at
~/.dsh/dsh-raw-html-state.json, restored after service restart.
Usage
- Click 「</> OFF」→「</> ON」 next to the composer send button to enable;
- Once on, HTML in new messages renders immediately; historical messages re-render on page refresh;
- The agent receives the injected VCP protocol → automatically outputs
#vcp-rootvisual containers; when off, the protocol is withdrawn → the agent falls back to plain Markdown. - VCP buttons
onclick="input('reply text')"fill the input and send on click.
Maintenance / Upgrading
- After each change:
node --check lib/client.js && node --check lib/index.js; client changes take effect on refresh; host changes require a dsh service restart. - A
dshupgrade overwrites the patched dist files → re-runpatch/install-all.cjs(idempotent; aborts without writing on anchor mismatch; backups in*.bak-installv6-<timestamp>). - Dependency declaration rule (lesson from the 2026-08-19 crash): every third-party package you
importmust be declared in package.json (dependencies or peerDependencies) — relying on whatever node_modules happens to exist is gambling your lifeline. Runnode tools/check-deps.cjsafter each change to verify. - To improve the design spec → edit
DESIGN.md(agents read it on demand) + sync the protocol text (buildProtocolTextinlib/index.js). - To add built-in fonts → edit the FONTS list in
tools/subset_fonts.pyand re-run (needs Python + fonttools + brotli); woff2 subsets are output toassets/fonts/.
Restore (undo patch)
# Rename the backup generated by the installer back (e.g. index-*.js.bak-xxx → index-*.js), then remove the plugin:
dsh plugin --profile web remove dsh-raw-html
Security notes
Once enabled, HTML from model output is rendered as UI. The patch filters scripts/events/dangerous
protocols (React rendering naturally never executes script; events only allow the controlled
onclick="input('...')" channel; script/iframe/object/embed and javascript: protocols are
dropped), but styles and external images remain reachable — enable only for trusted models.




