# dsh-cad — CAD Plugin for DeepSeek Harness ![dsh-cad banner](docs/img/banner.svg) [![homepage](https://img.shields.io/badge/homepage-dsh--cad-4D6BFE)](https://lau-mars.github.io/dsh-cad/) [![npm](https://img.shields.io/npm/v/dsh-cad)](https://www.npmjs.com/package/dsh-cad) [![downloads](https://img.shields.io/npm/dm/dsh-cad)](https://www.npmjs.com/package/dsh-cad) [![dsh](https://img.shields.io/npm/v/@deepseek-ai%2Fdsh?label=dsh)](https://www.npmjs.com/package/@deepseek-ai/dsh) [![Node](https://img.shields.io/badge/node-%3E%3D%2022-4D6BFE)](https://nodejs.org/) [![occt.ts](https://img.shields.io/npm/v/occt.ts)](https://www.npmjs.com/package/occt.ts) [![ansatz](https://img.shields.io/npm/v/ansatz-wasm?label=ansatz)](https://www.npmjs.com/package/ansatz-wasm) [![License: MIT](https://img.shields.io/badge/license-MIT-4D6BFE)](./LICENSE) [English](./README.md) | 简体中文 [DeepSeek Harness (dsh)](https://github.com/deepseek-ai/deepseek-harness) 的 CAD 插件: 在 Web UI 中提供**内嵌 3D/2D CAD 查看器**与**原生参数化建模工具族**(OCCT 内核), 让 agent 能够"边建边看"地完成 CAD 工作。 ## 预览 一次完整的建模会话:在对话中直接搭参数化装配体——先建 120×80×8、四角 R5 圆角的底板,再在四角放置 4 个螺栓实例——右侧常驻 CAD 面板全程实时跟踪 (带逐实例配色的零件树、ViewCube、"装配体"页签、5 实例 · 1,740 三角形)。 完成后导出结构化 STEP 文档,agent 回读文件自检——2 个实体、3 个产品、 2 个装配引用、1,125.00 mm³: ![dsh-cad 装配建模会话](docs/img/assembly-preview.png) ## 功能总览 | 能力 | 说明 | | --- | --- | | ⚙️ 单内核架构 | **occt.ts 为主建模内核**(真 BSpline、抽壳/拔模原生、质心),opencascade.js 仅作为加载失败时的降级后端;旧版的「抽壳后不可编辑」接缝消失——抽壳/拔模后可继续圆角/倒角/布尔 | | 🔍 CAD 查看 | STL / OBJ / STEP / IGES / BREP / DCPRT(3D),DXF / SVG(2D),右侧常驻面板交互视口(轨道旋转 / 缩放 / 线框 / 平移),对话中只留一行结果摘要 | | 🧭 CAD 编辑器交互 | Onshape 风格 ViewCube(26 区域点击定向)、悬停/点选面与边实时测量(面积 mm² / 长度 mm)、面+边 / 面 / 线框三种渲染模式、支架 / 法兰 / 轴 BRep 示例件一键切换 | | 🏗️ 参数化建模 | 基本体、轮廓拉伸、**放样**、**扫掠**、**旋转体**、布尔、全边圆角/倒角、**抽壳**、**拔模**、**阵列(线性/圆周)**、变换;轮廓支持**曲线段**(圆弧/圆为精确 BRep,B 样条为采样近似)—— OCCT 精确 BRep,非网格近似 | | ✏️ 命名草图 | 文档中独立的可命名轮廓(Sketch1…):`cad_sketch_new` / `edit` / `list` / `delete`;拉伸/旋转/扫掠**按名字引用**,`cad_sketch_edit` 原位改写定义并全量重放,所有引用特征级联重建——参数化闭环。草图以 Onshape 式**蓝色曲线 + 平面框**在视口中实时渲染(回改即刷新),并列于零件页签左侧的**特征树**(草图 + 特征、眼睛显隐、点选高亮实体) | | 🗂️ Codex 式文档页签 | 右侧显示区页签栏 + 「+」菜单:**零件**(Part Studio,默认)/ **装配体**(实例插入/移动/移除)/ **工程图**(真实隐藏线图纸),页签可关闭、常驻不丢状态 | | 📁 多文档 file 空间 | 工作区命名的建模文档(`.dsh-cad/docs/`),每个会话绑定自己的活动文档——新会话从空文档开始,不再继承历史遗留零件;面板上的文件夹按钮列出全部文档(预览 / 删除),对话中用 `cad_doc_new` / `cad_doc_open` 切换建模目标 | | 📐 工程图 | GB 第一角布局:主视图 / 俯视图 / 左视图 + 轴测图,**occt.ts** 内核(npm 依赖)真实隐藏线消除(虚线);图框、标题栏、总尺寸标注、标准比例系列;导出 SVG / DXF | | 🔗 约束求解与运动 | 集成 **Ansatz** 几何约束求解器(**`ansatz-wasm` 一条命令即可**:`npm install ansatz-wasm`,零 Rust 工具链 / 零原生二进制 / 零依赖):实体/约束建模(装配实例 ↔ rigid3 位姿自动映射)、求解回写、DOF/残差/冗余/建议全量诊断(面向 LLM 的中文报告)、参数扫描运动学(`cad_constraint` / `cad_solve` / `cad_motion`) | | 📐 几何测量 | 精确体积(mm³)、包围盒、三角统计、DXF 图层 | | 📤 按需导出 | STEP(参数化)/ STL(网格),仅在用户要求时写文件 | | 🖥️ 常驻 CAD 显示区 | 会话页右侧常驻面板:Codex 式页签(零件 / 装配体 / 工程图),建模时实时跟踪最新模型 | | ⚡ 直通渲染管道 | worker 网格 → 内存二进制 → three.js typed-array,零 base64 / 零中间文件 / 零每步落盘 | | 💾 建模文档持久化 | 操作日志(JSON)+ 防抖磁盘镜像,进程重启后自动重放恢复 | | 🖼️ 图片 → 轮廓 | PNG 草图/截图 → Otsu 二值化 → 轮廓追踪 → 可直接拉伸的多边形(`cad_image_profile`) | | 🔌 FreeCAD 执行器 | 在外部 FreeCAD 控制台运行同一 op 族(STEP 输入/输出闭环);需本地安装 | | ☁️ Onshape 执行器 | 经**签名 REST API** 在 **Onshape** 云端运行同一 op 族——零本地安装:每个 op 编译为一个**标准 Onshape 特征**推入目标 Part Studio(无需 Feature Studio 配置)。回传分三级:默认按零件的廉价 STL、`readback: "step"` 精确 BRep 命名网格(服务端 STEP 翻译 + 本地 OCCT 解析)、`readback: "none"` 只建模型回文档链接(约 3 次调用,最省配额)。导出支持 `.stl` / `.step` / `.x_t`(Parasolid 原生内核 BRep)。配额感知错误区分密钥问题与免费档冷却;始终返回 Onshape 文档链接 | ## 安装 插件已发布到 npm,一行命令即可: ```sh dsh plugin --profile web add dsh-cad ``` 安装器会通过 `dsh.bundle` 清单自动应用包内自带的 `cordis.patch.yml`,无需手工改任何配置。 ### 版本要求 - **Node.js** 与 **dsh CLI**(`@deepseek-ai/dsh`)的最低版本以顶部徽章和 `package.json` 的 `engines` 字段为准——正文不再写具体版本号,避免过时 ### 从源码安装(开发模式) ```sh git clone https://github.com/LAU-MARS/dsh-cad.git cd dsh-cad npm install && npm run build && npm test # 依赖含 occt.ts(工程图真实消隐内核,~20MB wasm) npm install -g @deepseek-ai/dsh pnpm dsh web # 首次启动初始化 profile 后 Ctrl-C dsh plugin --profile web add /path/to/dsh-cad dsh web ``` patch 内容以包根目录的 `cordis.patch.yml` 随包分发,安装器经同一条 `dsh.bundle` 清单自动应用。 设置 `DEEPSEEK_API_KEY` 后对话即可使用,例如: - “打开 bracket.stl 看看” → `cad_view` - “画一个 100×60×5 的板,中间打 ⌀20 孔,四角 R2 圆角,加 ⌀16 高 20 凸台,导出 plate.step” → `cad_create_prim` + `cad_boolean` + `cad_fillet` + `cad_export`,每步 3D 页签实时更新 - “堆一个雪人” → 球体 + 圆锥鼻子 + 圆柱帽子(`at`/`axis` 精确定位) - “再放两个 b1,一个转到 90 度” → `cad_assembly_insert` + `cad_assembly_move`,装配体页签实时更新 - “给 b1 出一张 A3 工程图,导出 dxf” → `cad_drawing`(三视图 + 轴测 + 虚线隐藏线 + 尺寸标注)→ `cad_export` `.dxf` ## 模型工具族 | 工具 | 说明 | | --- | --- | | `cad_view` | 打开 CAD 文件,渲染交互式查看器卡片 | | `cad_info` | 只读几何元信息(格式/数量/包围盒/单位/图层) | | `cad_create_prim` | 基本体(mm,Z-up),`at` 定位、`axis` 定向(精确轴角旋转) | | `cad_sketch_new` | 新建命名草图(Sketch1…):{start, segments} / {circle} / 平面点列——供轮廓特征按名引用 | | `cad_sketch_edit` | 回改草图:定义 op 原位改写 + 日志全量重放,所有引用特征级联重建 | | `cad_sketch_list` | 列出文档草图(名称 / 形式 / 规模) | | `cad_sketch_delete` | 删除草图(仍被特征引用时拒绝) | | `cad_extrude_profile` | XY 平面闭合轮廓沿 +Z 拉伸成实体——内联点列/曲线段/圆,或引用命名草图(`sketch`) | | `cad_loft` | 放样:多个闭合截面(各自平面内的 [x,y,z…] 环)蒙皮成体,截面形状/点数可不同,`ruled` 直纹 | | `cad_revolve` | 旋转体:闭合轮廓绕轴回转(profile 坐标 = (半径, 高度),支持曲线段——圆角轮缘精确),`angle` 角度可选;可引用命名草图 | | `cad_chamfer` | 倒角:全锐边等距离斜切(mm) | | `cad_pattern` | 阵列:线性(delta 间距)或圆周(主轴 + at 轴点 + 总角度),生成副本体,可再 fuse 合并 | | `cad_shell` | 抽壳:壁厚向内生长、外表面保留;`open` 为开口面的外法向列表(空 = 封闭内腔)。经 occt.ts 内核执行,结果为**托管体** | | `cad_draft` | 拔模:壁面绕中性面倾斜 `angle` 度(脱模斜度),`direction` 为拔模方向,默认自动选平行于该方向的壁面。经 occt.ts 内核执行,结果为**托管体** | | `cad_sweep` | 扫掠:闭合 2D 轮廓沿 3D 路径([x,y,z…])扫出实体;轮廓自动置于路径起点垂面,无需手工定向;可引用命名草图 | | `cad_boolean` | fuse / cut / common(经典打孔:plate cut cylinder) | | `cad_fillet` | 全锐边等半径圆角 | | `cad_transform` | 平移 / 欧拉旋转 / 镜像 | | `cad_volume` | 精确 BRep 体积(mm³) | | `cad_drawing` | 工程图:主/俯/左 + 轴测四视图,隐藏线(虚线)、图框、标题栏、总尺寸、标准比例,A4/A3 | | `cad_assembly_insert` | 将零件以实例插入装配体(`at` 定位、`rotate` 定向) | | `cad_assembly_move` | 设置实例绝对位置/姿态 | | `cad_assembly_remove` | 从装配体移除实例(零件保留) | | `cad_constraint` | 声明约束模型:实体(含装配实例绑定)+ 约束(distance/angle/mate/coaxial…),持久化于操作日志 | | `cad_solve` | Ansatz 求解并回写装配位姿;返回 DOF 剩余/残差/冗余/建议全量诊断 | | `cad_motion` | 运动学扫描:驱动一个约束值从 from 到 to 逐帧求解,应用末帧位姿并返回运动表 | | `cad_export` | 导出 STEP / STL / DCPRT(原生可重放零件文档)到工作区路径;`target: "assembly"` 导出装配体 STEP,`target: "drawing"` 导出工程图 SVG / DXF | | `cad_delete` | 删除 body | | `cad_docs` | 列出工作区建模文档(id / 名称 / 体数 / 更新时间,标记当前活动文档) | | `cad_doc_new` | 新建命名文档并设为会话建模目标(多零件项目从这里开始) | | `cad_doc_open` | 打开已有文档(按 id 或名称)作为会话建模目标——body 精确重放 | | `cad_doc_rename` | 重命名文档 | | `cad_doc_delete` | 永久删除文档(需 `confirm: true`) | | `cad_freecad` | 在外部 FreeCAD 执行器上运行 op 程序(可选 STEP 输入/导出) | | `cad_fusion` | 在外部 Fusion 360 执行器上运行 op 程序(GUI 桥;可选导出) | | `cad_onshape` | 在 Onshape 云端运行 op 程序(签名 REST API):新建或驱动文档、返回文档链接;`readback: "step"` 回传精确 BRep 网格;导出 `.stl` / `.step` / `.x_t`(Parasolid) | | `cad_image_profile` | PNG → 轮廓 → 可直接拉伸的多边形点集 | | `cad_script` | 确定性脚本求值(轮廓点列/圆弧坐标等几何计算):`js` 在进程内 Node vm 运行(无需 shell——宿主 shell 不可用时仍可用),`py` 走系统 Python | 每步建模后:对话中的结果行原地更新(稳定 viewId + 版本化 URL), 右侧 "零件" 页签实时跟踪最新模型。 ## 连接器(规划中) 建模主要由 **occt.ts** 内核承担(opencascade.js 为降级后端)(浏览器内的 OCCT 内核,零安装); 下表连接器指未来以**外部 CAD 引擎作为执行器**驱动同一工具族: | 连接器 | 套件 | 平台 | 状态 | | --- | --- | --- | --- | | **内置内核** | 基于 OCCT + WebGL 的 CAD 建模内核,浏览器内运行——零安装 | 全平台(WebGL 渲染) | ✅ 内置 | | FreeCAD | 开源参数化套件——可经其 Python API 作为本地执行器(控制台 + GUI 窗口双模式) | Windows / macOS / Linux | ✅ 可用(需本地安装) | | Fusion 360 | Autodesk CAD/CAM——常驻 Add-In + spool 桥(无 headless,Fusion 窗口即查看器) | Windows / macOS | 🧪 实验性(`cad_fusion`) | | SolidWorks | 达索系统的主流 3D CAD,COM/.NET 自动化 | 仅 Windows | 🚧 Windows demo 脚手架(`scripts/solidworks-bridge/`) | | Onshape | PTC 云原生 SaaS CAD,完全在浏览器——签名 REST API(cad.onshape.com 或私有 chamber 域名);每个 op 编译为标准 Onshape 特征推入 Part Studio,结果按零件回传 STL + 质量属性,云端即查看器 | 全平台(浏览器) | ✅ 可用(`cad_onshape`;设置 `DSH_ONSHAPE_ACCESS_KEY` / `DSH_ONSHAPE_SECRET_KEY`) | | 中望3D(ZW3D) | 中望软件的一体化 CAD/CAM | Windows / Linux | 🚧 规划中 | | 浩辰3D | 浩辰软件的 3D CAD | Windows | 🚧 规划中 | 所有外部引擎实现同一 **GeometryExecutor 契约**(`available()` / `run(op程序) → 网格`), WebGL 显示层因此永不改变——更换后端只影响生成几何的质量。 ## 架构 ``` cad_view(path) 建模工具(cad_create_prim 等) → 导入 worker(occt-import-js) → 建模 worker(opencascade.js WASM) → CadScene JSON(base64-f32) → BRep 精确几何 + 网格化 → GET /dsh-cad/scene/ → 内存二进制场景(f32/u32 打包) → GET /dsh-cad/bin/ ↓ 会话 presentationMeta(viewId + 版本化 URL)↓ 浏览器卡片 + 常驻 "3D" 页签(three.js / SVG,Z-up,XYZ 轴) ``` - **两个 worker**:导入(occt-import-js,只读 STEP/IGES/BREP)与建模(opencascade.js, 完整 OCCT)分离,均惰性启动;embind 重载构造器的 `_N` 后缀约定封装在 `src/modeling/occt-adapter.cjs`(全部经运行时实证) - **直通管道**:建模场景零 base64 / 零 JSON 大数组 / 零每步落盘(磁盘镜像 1.5s 防抖, 仅服务重启回放);`cad_export` 是唯一的显式文件导出 - **建模文档**:`/.dsh-cad/model.json` 操作日志,重启后重放恢复全部 body - **工程图消隐内核**:隐藏线由 **occt.ts**(npm 依赖,`npm i occt.ts`)执行 真实 OCCT 消隐,无替代引擎、缺失即报错。相对 opencascade.js 的新增 API: `hiddenLines()` 真实消隐线、STEP/BRep 字节级 `readStep`/`readBrep`/`writeStep`/ `writeBrep`(无需 MEMFS)、自带特征边提取的网格化、`hasError()`/`lastError()` 错误契约。几何以 STEP 字节跨内核交换,投影线段重映射进图纸坐标系。内核 dist 解析顺序:`DSH_OCCTJS_DIST` 环境变量 → Node 自带的 `occt.ts` 依赖解析(沿所有 父级 node_modules 向上查——npm/yarn 扁平安装与 pnpm 符号链接布局都能命中)→ `/../opencascade-ts/dist`(兄弟检出)→ `vendor/` → `node_modules/opencascade-ts` - **约束求解(Ansatz)**:求解器是 npm 依赖 **`ansatz-wasm`**(wasm-bindgen 构建,单包 ~538KB、零依赖)——安装 dsh-cad 即自动获得,也可单独 `npm install ansatz-wasm` 升级;**无需 Rust 工具链、无需原生二进制、跨平台**。 解析顺序:npm 包(node_modules)→ `DSH_ANSATZ_WASM` 目录 → 兄弟 Ansatz 检出的 pkg-node。求解器以 JSON 信封契约通信,工具层错误(`unsupported_constraint` 等) 原样透出给 LLM。装配实例位姿(平移 + XYZ 欧拉度)与求解器 rigid3(平移 + 指数映射 旋转,弧度)双向映射。求解器能力按阶段推进(当前支持点到原点距离),管道契约 已就绪、无需随求解器成长改动 - **单内核架构**:建模主内核为 **occt.ts**——prims/曲线段轮廓 (真 BSpline 插值)/放样/扫掠/旋转/布尔/圆角/倒角/抽壳/拔模/镜像(scale(-1)+ 旋转 π 组合)/质心全在一个会话内,工程图 HLR 直接吃 shape(零 STEP 中转), 抽壳后继续编辑无缝(旧托管接缝已删除)。opencascade.js 保留为**降级后端** (occt.ts 加载失败时自动启用)。装配体 STEP 导出为**结构化文档**(occt.ts `writeStepDocument`):一个根产品 + 每实例一个命名、带位姿的子产品—— 实例分离在文件中保留(STL 仍为单一熔合网格;降级后端同样走 fuse)。fuse 路径下实例分离仅保留在装配场景/文档中。面选择按 `describe()` 平面法向 匹配(±法向取外侧投影最大者) - **客户端**:esbuild 单文件 CJS 工厂(three.js 内联 ~560KB,react 由宿主模块表提供), Z-up CAD 惯例,带 XYZ 轴标签与地面网格的空场景常驻显示 ## 测试 ```sh npm test # 全套:转换器 / 建模 worker(体积精确断言)/ DCPRT 往返 / FreeCAD + Onshape 执行器 / 图片轮廓 / 二进制管道 / 文档持久化 node test/m0-kernel-check.cjs # OCCT 内核 API 冒烟 node test/route-check.mjs # JSON 场景路由层 node test/visual/serve.mjs # 浏览器卡片/页签视觉验证页(http://127.0.0.1:3987) ``` 覆盖的代表性断言:布尔打孔体积精确等于解析值(28429.20 mm³)、L 型轮廓拉伸 3000 mm³、球/锥/环带 `at`/`axis` 定位的体积与包围盒翻转、二进制打包 8 字节对齐、 STL 导出往返(导出 → 一期解析器读回),以及 DCPRT 文档往返 (序列化 → OCCT worker 重放 → 精确包围盒)。 ## 已知限制 - DWG(闭源)不支持;DXF bulge 弧以弦线近似;glTF/3MF 查看未实现(结构已预留) - `cad_fillet` 为全边等半径(embind 下按边选择不稳定);chamfer 未实现 - 草图拉伸仅支持多边形轮廓(圆弧轮廓用布尔组合圆柱/圆环构造) - dsh 框架限制:已挂载的 single 槽(右侧 details 面板本体)不响应后注册组件, 故常驻显示区以 "3D" 视图页签提供(list 槽,官方组合方式) - 宿主读取 CAD 文件使用 node:fs(平台 fs 服务仅支持 UTF-8 文本,无法承载二进制) ## 社区 | QQ 群(🇨🇳 国内) | 飞书群(🇨🇳 国内) | X / Twitter(🌍 国际) | Discord(🌍 国际) | | --- | --- | --- | --- | | `485038246`(加群备注 dsh-cad) | 🚧 敬请期待 | 🚧 敬请期待 | 🚧 敬请期待 | ## 贡献者 由提交历史自动生成,感谢每一位贡献者! [![Contributors](https://contrib.rocks/image?repo=LAU-MARS/dsh-cad)](https://github.com/LAU-MARS/dsh-cad/graphs/contributors) ## License MIT