dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
侧边栏 DWG/DXF 预览 · Sidebar DWG/DXF preview — DeepSeek Harness (DSH) 插件:在侧边栏的文档预览里直接打开 .dwg / .dxf 工程图纸,宿主侧用 LibreDWG(WASM) 解码、再用自带零依赖渲染器画成矢量 SVG。 A DSH plugin that previews DWG/DXF drawings inside the sidebar document preview.
DeepSeek Harness(DSH)桌面端的文档预览插件:在工作区里点开
.dwg/.dxf图纸, 右侧预览标签直接显示矢量图形 —— 可拖拽平移、Ctrl/⌘ + 滚轮缩放、一键适应宽度。
DSH 自带的预览只认识文本与图片,DWG 图纸点开只会是「无法预览」。这个插件补上那一步:宿主侧用 LibreDWG(编译成 WebAssembly)把 DWG 解成 DXF,再用本仓库里零依赖的渲染器 lib/dxf2svg.mjs 画成一张自包含的 SVG;浏览器侧只负责显示这张图,不解码、不加载任何第三方查看器库。DXF 是纯文本,不需要 LibreDWG,直接进渲染器。
上图由 test/sample.dxf 生成(node tools/make-example.mjs),覆盖下面列出的图元类型。
.dwg 或 .dxf,右侧文档预览标签里的内容就是它 —— 槽位 sidebar.right.tab.document,body 键 @local/dsh-dwg-preview/dwg。dwg-preview(见 cordis.patch.yml)。插件不注册设置页,所以没有 order。sidebar-documentpreview 插件提供的注册表登记一个渲染器,声明后缀 dwg 与 dxf、priority: 'extension'(按后缀认领)、loading: 'bytes-complete'(要整份文件,不是流)。其它后缀不受影响。/api 通道上):| 方法 | 路径 | 响应 |
|---|---|---|
| GET | /api/dwg-preview/ping | 200 {"ok":true,"plugin":"dsh-dwg-preview","cache":<已缓存张数>} |
| POST | /api/dwg-preview/svg | 200 {"ok":true,"kind":"dwg"|"dxf","svg":…,"stats":…} |
| POST | /api/dwg-preview/svg | 400 {"ok":false,"code":"EMPTY","message":"文件内容为空"} |
| POST | /api/dwg-preview/svg | 413 {"ok":false,"code":"TOO_LARGE","message":"文件超过 64 MB,预览已跳过"} |
| POST | /api/dwg-preview/svg | 500 {"ok":false,"code":"FAILED","message":…} |
require('react');DWG 解码需要 @mlightcad/libredwg-web(见文末许可)。content.kind === 'bytes')。POST 到 /api/dwg-preview/svg,附带 x-dwg-name(百分号编码的文件名,只作旁注 —— 宿主的格式判定不看它)。AC10xx 开头是 DWG;前 8 KB 里同时出现 SECTION 与 HEADER/ENTITIES 是 DXF;都不是就报 FAILED。dxfToSvg()。viewBox + 背景 rect + 一个翻转 g),整份字符串返回给浏览器,浏览器用 Blob URL 显示。为什么要绕这一圈:LibreDWG 的 wasm 约 9.5 MB,而 DWG 解码是 CPU 密集的同步调用。放进宿主进程,页面侧只处理一张图片;放进页面,每个预览标签都要为它付一份代价。DXF 路径是纯函数,所以能完全离线测试。
渲染器覆盖的图元:LINE、LWPOLYLINE(含 bulge 圆弧)、POLYLINE + VERTEX、CIRCLE、ARC、ELLIPSE、TEXT、MTEXT、ATTRIB、INSERT(嵌套块、行列阵列、旋转与缩放)、HATCH(多段线边界与边边界:直线、圆弧、椭圆弧、拟合点)、SOLID / 3DFACE、POINT、DIMENSION(走它的匿名块)。列表之外的实体被忽略,不报错也不画。
$EXTMIN / $EXTMAX;缺失或退化时用模型空间坐标的原始跨度。块内几何不参与范围计算 —— 有些块带着远在图纸之外的垃圾几何,否则会把视图撑坏。最后加 2% 内边距。stats.__stray(图元级)与 stats.__skippedOutside(总数,含被丢掉的阵列肢体),界面不显示。70 位 1(冻结)的图层会被跳过。A 命令;ARC 用一段 A;HATCH 的圆弧边界按每 10° 一段折线近似(单条最多 64 段),椭圆弧按每 15° 一段。scale(1 -1) 翻回来,所以字是正的。MTEXT 只做有限清洗(\P 换行、\A…; 一类格式码、{}、\~),格式与堆叠分数会丢;不嵌入字体,字形靠系统字体(SimSun, 'Microsoft YaHei', sans-serif),换机器字形会变;不做折行与分栏,也不做 SHX 大字体。vector-effect="non-scaling-stroke" 在任何缩放下保持 1 像素。顺带说清楚计数口径:预览页上的「N 个图元」是渲染器各类型计数之和;ATTRIB 在图元遍历与图元渲染两处各计一次,所以含属性块的图纸会多算一个。它只是显示口径,不影响绘制。
本插件是一个标准 DSH bundle:package.json 里声明了 dsh.bundle.patch 与 dsh.client,装进任何 profile 都走同一条路。先装好 DSH 桌面端(deepseek.com/download),然后下面任选一种。
https://github.com/linanbuan/dsh-dwg-previewSource code (zip))整个安装由 Harness 自己的插件管理器完成:把这个包写进当前 profile 的 dsh.profile.bundles,并挂上宿主半边。桌面端装插件不需要命令行,也不需要手改 profile 文件。
把仓库地址或本机目录直接交给任意会话里的 Agent,它会调用 plugin_manager 工具(action: install_bundle)走同一条路。这是官方给第三方插件推荐的安装方式。
装了 dsh CLI 的机器上:
dsh plugin --profile <profile 名> add <spec>
<spec> 与方式一相同(包名、Git 地址、压缩包链接或本地路径);参数以 dsh plugin --help 的实际输出为准。
profile 目录默认在 ~/.dsh/profiles/<profile 名>。把包放进去,并在 profile 自己的 package.json 里登记两处:
"dependencies": { "@local/dsh-dwg-preview": "link:<本目录绝对路径>" },
"dsh": { "profile": { "bundles": [ "…", "@local/dsh-dwg-preview" ] } }
手改 profile 文件要过权限审批,写坏会让 Harness 起不来,所以正常安装请走前面三种。手工安装时依赖不会自动装:宿主半边需要 @mlightcad/libredwg-web,你要自己把它装进 profile(方式一至方式三由 Harness 按 dependencies 装)。
documentPreviews 渲染器与 sidebar.right.tab.document 的 body,随启动图加载;由 HMR 更新时不需要刷新页面。/api/dwg-preview/* 路由。安装时若提示需要重启,重启 DeepSeek Harness 应用(不是刷新页面)—— 桌面 profile 的 base 组合包以 root: [] 启用 HMR(只监听显式注册的配置),而 HMR 的忽略规则默认含 **/node_modules,装在 node_modules 下的插件代码不在监听范围内。@deepseek-ai/dsh-client-ui-sidebar-documentpreview 插件提供的注册表上(dsh.client.inject 声明了这份加载顺序)。注册表还没就绪时,浏览器半边会在 6 秒内每 150 毫秒重试一次(最多 40 次),不会静默丢掉渲染器。GET /api/dwg-preview/ping。临时关掉(在 profile 自己的 cordis.patch.yml 里,或直接用插件页那一行的开关):
- id: dwg-preview
disabled: true
彻底移除:插件页 → 这个包 → 卸载,它会把包从 profile 的依赖与 dsh.profile.bundles 里去掉。
apply());浏览器半边在开发时由 HMR 更新。@mlightcad/libredwg-web 的 wasm,同样跨平台。本插件在 Windows 桌面端 + DSH 0.1.7-rc.2 上实测过。connection.fetch.register、slots.register、locale.register 与 documentPreviews 注册表都是 Harness 的内部形态,官方没有兼容承诺,版本升级后可能改名或改形。.mount.log 挂载标记(已 gitignore,只为排障),它不写任何文件;不读你的会话、不读凭据、不联网、无遥测。@mlightcad/libredwg-web(GPL-3.0),它由 Harness profile 按 dependencies 单独安装,本仓库不分发它。若你把本插件与它打进同一份 bundle 再分发,这份组合受 GPL-3.0 约束;本仓库自己的代码是 MIT。400 EMPTY、超过 64 MB 413 TOO_LARGE、格式认不出或解码失败 500 FAILED,界面显示「预览失败」与原因;路由把异常都收在响应里,不会把宿主进程带崩。TOO_LARGE。上限以内的大图纸仍会占用宿主进程的内存,并让它同步忙上一会儿(渲染是同步的)。test/sample.dxf 是为这个仓库手写的,不含任何真实图纸数据。node test/selfcheck.mjs # 或 pnpm test
node tools/make-example.mjs # 重新生成 docs/example.svg(或 pnpm run example)
自检不需要网络、不需要 Harness、不需要 React、不需要安装任何依赖,纯 Node 跑完 31 项,全部通过时打印 31/31 checks passed 并以 0 退出,任何一项失败就以非 0 退出(可直接接 CI)。注意 pnpm test 会走 pnpm 自己的流程:它第一次会按 dependencies 真的装一遍依赖(于是写 node_modules/ 与 pnpm-lock.yaml,两者都在 .gitignore 里、不随仓库分发),装上 @mlightcad/libredwg-web 之后,DWG 那一项检查会自动跳过并打印原因 —— 它只能在装好依赖的 profile 里验证真实解码。它做的事:
test/sample.dxf,逐类型钉住 stats(LINE 11、CIRCLE 5、ARC 1……)与 SVG 结构:viewBox 的具体数值、唯一的根 g、translate(0 80) scale(1 -1) 翻转、non-scaling-stroke、标签成对闭合;<text>(共 4 个)、都在翻转组里翻正、XML 特殊字符被转义;stats.__stray)、图层颜色取绝对值、冻结图层被跳过、空图纸抛错;client.js:后缀(dwg/dxf)、priority: 'extension'、keyed body(sidebar.right.tab.document + @local/dsh-dwg-preview/dwg)、zh/en 字典键一致、样式只装一次,并断言 require 只被 'react' 调用过(一旦它去 require 任何官方客户端包,自检当场失败);fetch 真跑一遍视图:字节以 POST 发到 /api/dwg-preview/svg、x-dwg-name 是百分号编码、返回的 SVG 变成 Blob URL、图元总数显示为 31 个图元;放大 / 缩小 / 适应宽度、Ctrl + 滚轮、拖拽平移各自的结果都断言到百分比与滚动偏移;ctx 驱动 index.js 的 apply() 并真调用两条路由:ping、DXF 往返(同一份文件第二次走缓存)、空体 400 EMPTY、垃圾内容 500 FAILED、超过 64 MB 413 TOO_LARGE(用零填充的 SharedArrayBuffer 视图把请求体做到 64 MB + 1 字节,不复制、不占 64 MB 内存)、以 AC10xx 开头的体走 DWG 分支;package.json 的 license / repository / keywords / files 覆盖树里每个文件、engines.node 且没有 engines.dsh;.gitignore 覆盖 node_modules/、*.log、.mount.log;两份 README 的章节、代码围栏与表格行数一致;全树扫描没有密钥、没有个人绝对路径、版权人姓名只出现在 LICENSE / package.json / 两份 README 里。它不能证明什么,说清楚:
@mlightcad/libredwg-web 是本仓库之外的运行时依赖(见许可),这里只验证「以 AC10xx 开头的内容会走 DWG 分支,且依赖缺失时如实报 FAILED」。真正的 DWG 解码只能在装好依赖的 profile 里试;自检检测到该依赖存在时会跳过那一项并打印原因。__ModuleLoader__ 与一个最小 hook 运行时上,不是 DOM,也没有官方注册表,因此字体、paint 与 Blob 的真实语义都没被覆盖。documentPreviews、slots、locale、connection.fetch.register 在自检里都是替身;HMR 与重启规则也无法在这里验证。package.json bundle 清单(dsh.bundle.patch + dsh.client)
cordis.patch.yml 一行 insert:装载宿主半边
index.js 宿主半边:两条 /api/dwg-preview/* 路由、内容判定、sha1 缓存
client.js 浏览器半边:documentPreviews 渲染器 + sidebar.right.tab.document 视图(手写 lazy CJS,只用 react)
lib/dxf2svg.mjs 零依赖的 DXF → SVG 渲染器(dxfToSvg(text, options))
icon.svg 插件图标
docs/example.svg 由 test/sample.dxf 生成的演示图(本文顶上那张)
test/sample.dxf 样例图纸:覆盖上面列出的 14 类图元
test/selfcheck.mjs 自检(31 项)
tools/make-example.mjs 重新生成 docs/example.svg
@mlightcad/libredwg-web(GPL-3.0):DWG 解码依赖,即 LibreDWG 的 WebAssembly 封装(上游 LibreDWG 同样是 GPL-3.0)。它是 Harness profile 按 dependencies 单独安装的 npm 包,本仓库不分发、不内置、也不把它打进任何产物。把本插件与它打包在一起分发,这份组合就受 GPL-3.0 约束;本仓库自己的代码仍是 MIT(见 LICENSE)。index.js、client.js、lib/dxf2svg.mjs 与 test/sample.dxf 都是为这个插件写的;ACI 颜色表的取值来自 DXF 规范本身。connection、slots、locale 服务,以及官方 sidebar-documentpreview 插件提供的 documentPreviews 注册表。浏览器半边自己不 require 任何官方客户端包,也不加载任何第三方查看器库(没有 three.js、没有 dxf-parser、页面里没有 wasm);dsh.client.inject 只是声明加载顺序,不是代码引用。MIT © 2026 linanbuan