dsh-eda-mcp 0.7.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/docs/schematic-workflow.md +119 -0
- package/docs/tools.md +11 -3
- package/dsh-eda-bridge-extension-0.4.6.zip +0 -0
- package/jlc-extension/api-bridge.js +40 -3
- package/jlc-extension/extension.json +1 -1
- package/lib/bridge.mjs +997 -25
- package/lib/index.js +148 -4
- package/package.json +2 -2
- package/src/bridge/design-intake.ts +133 -0
- package/src/bridge/design-rules.ts +16 -3
- package/src/bridge/index.ts +568 -21
- package/src/bridge/netlist-erc.ts +305 -0
- package/src/bridge/schematic-audit.ts +131 -0
- package/src/bridge/workflow-guide.ts +23 -3
- package/src/guidance.ts +5 -0
- package/src/skills-content.ts +119 -0
- package/test/design-intake.test.ts +40 -0
- package/test/netlist-erc.test.ts +90 -0
- package/test/schematic-audit.test.ts +71 -0
- package/test/skills.test.ts +1 -1
- package/dsh-eda-bridge-extension-0.4.2.zip +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0 — 2026-10-20
|
|
4
|
+
|
|
5
|
+
第一个稳定版。0.7.4 之后这一轮把"能画"推进到"画得对、画得像参考设计、交付有证据":工具 106 → **109**,单测 6 → **8 套**,线协议 0.4.2 → **0.4.6**。
|
|
6
|
+
|
|
7
|
+
### 新增工具
|
|
8
|
+
|
|
9
|
+
| 工具 | 作用 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `eda_design_intake` | 开工前参数问卷:6 个部分 22 问(14 个 critical),每问带 why/options/fallback;答复写进工程描述持久化(`[dsh-eda-spec]`),下次会话自动读回 |
|
|
12
|
+
| `eda_schematic_audit` | 原理图几何审计:符号出框、压标题栏、符号互相压住、偏离 10 单位栅格、标签落进符号体 |
|
|
13
|
+
| `eda_netlist_erc` | 网表级电气烟雾测试(12 → **15 项**):位号重复、悬空脚、单端点网络、器件全脚同网、电源脚悬空、缺去耦、USB D± 成对、晶振负载电容、复位 RC、BOOT 下拉、Type-C CC 下拉,以及 **BOM 可下单性**(缺料号/排除出 PCB/缺封装) |
|
|
14
|
+
| `eda_delivery_checklist` | 交付检查:ERC + PCB 审计/DRC + Gerber + BOM 一次串完,逐步 PASS/FAIL,可 `outPath` 落 Markdown 报告 |
|
|
15
|
+
| `pcb_draw_text` | PCB 丝印/装配/文档层文本 |
|
|
16
|
+
| `pcb_draw_mounting_hole` | 非金属化定位孔/槽孔(`ELLIPSE` 焊盘 + `ROUND`/`SLOT` 钻孔) |
|
|
17
|
+
| `eda_capture` | 文档渲染成 PNG(可 `cleanup:true` 删除本会话写过的临时截图) |
|
|
18
|
+
| `eda_pcb_canvas_origin` | 画布坐标 ↔ 数据坐标(官方:界面显示画布、API 用数据),可 `align:true` 归零 |
|
|
19
|
+
|
|
20
|
+
### 修掉的真问题
|
|
21
|
+
|
|
22
|
+
- **能力边界错报**:`eda_list_api_methods` 报桥接本地副本却宣称是扩展白名单,`eda_api_call` 又被同一份副本前置拦截 → 改为**以扩展自报为准**(`dsh.internal.listApiMethods`),桥接不再预拦,永远不比扩展更严。
|
|
23
|
+
- **覆铜"无法创建"其实是 API 用错**:官方要求**复杂多边形**(`createComplexPolygon`)且建完必须 `rebuildCopperRegion()` 才计算铜皮;之前用单多边形,故一直失败(我一度误判为应用限制)。
|
|
24
|
+
- **定位孔创建失败**:`pcb_PrimitivePad.create` 必须给 `pad` 形状,且槽孔只能用 `ELLIPSE(长,宽)`(`OBLONG`/`RECTANGLE` 会被拒)。
|
|
25
|
+
- **网络标签降级时多余文本**:`createNetLabel` 不可用时过去同时放 stub 与纯文本;现在默认只留 stub,`textLabel:true` 才加文字。
|
|
26
|
+
- **PCB 网络校验**:未知网络的走线/过孔曾被接受(留下幽灵网络),现写入前用 `pcb_Net.getAllNetsName` 校验。
|
|
27
|
+
- **导出编码/分发门**:BOM 按 BOM 判编码(UTF-16LE 可读);分发门同时接受 `FILE_METHODS`(Gerber/BOM/网表/截图原本全被挡)。
|
|
28
|
+
- **参考基线校准暴露我的两条误报**:EDA 自生成网络名 `$1N6954` 被判非法、官方示例标准的 15 mil 被判"不在 0.05 mm 步进"(另有 9.81 mil 舍入噪声)。
|
|
29
|
+
|
|
30
|
+
### 规则与文档
|
|
31
|
+
|
|
32
|
+
- 技能从 12 章扩到 **17 章**:第 0 章(开工前问参数)、9b(PCB 设计工艺)、9c(外部对照与失败模式)、9d(验证与交付三件套)、第 12 章(环境与生效范围)。
|
|
33
|
+
- **参考基线**(本地实测官方 `示例工程_快速入门`):走线 98 条用 **15/25 mil**、覆铜 1、**丝印文本 19**;据此给 audit 增加 `silkscreen-text` 与 `mounting-hole` 检查,并把 12/15/25 mil 列为标准档。校准后官方示例 **0 违规 / 0 警告**,本机 STM32 板 0 违规 / 4 警告(5V 线宽偏细、无覆铜、无丝印、无定位孔)。
|
|
34
|
+
- 外部对照来源写进技能:HWE-Bench(执行驱动验证)、6 模型×嘉立创 EDA 横评、KiCad sch-api #104(标签落点)、ST AN4488/AN2586、TI USB Type-C 参考设计、IPC-2221/7351。
|
|
35
|
+
- 系统提示新增四条硬规则:开工先问参数、看图判据(4 个必看时机 + 看完清理)、布线/投板前跑 ERC、交付前跑 checklist。
|
|
36
|
+
- 截图是临时文件:`eda_capture` 记录本会话写过的路径,`cleanup:true` 只删这些路径。
|
|
37
|
+
|
|
38
|
+
### 门禁
|
|
39
|
+
|
|
40
|
+
typecheck 0 · **8 套单测全过**(node-runtime/config-values/design-rules/seams/eda-launch/skills/netlist-erc/schematic-audit/design-intake 中新增 3 套)· contract-check PASS(109 工具 / 109 schema / 103 API 调用面)· build 0 · `guard:bundle` PASS · `docs/tools.md` 109 工具 0 未分组 · `docs/schematic-workflow.md` 286 行 / 17 章。
|
|
41
|
+
|
|
42
|
+
### 未在真机验证(诚实记录)
|
|
43
|
+
|
|
44
|
+
线协议 0.4.5/0.4.6 的改动(覆铜复杂多边形 + `rebuildCopperRegion`、canvas-origin 四个方法)以及本轮四个新工具,发布时扩展处于断开状态,**未做真机回归**。使用前请导入 `dsh-eda-bridge-extension-0.4.6.zip` 并重启 EDA,然后按 9d 章跑一遍 `eda_delivery_checklist`。
|
|
45
|
+
|
|
3
46
|
## 0.7.4 — 2026-10-20
|
|
4
47
|
|
|
5
48
|
发布后补:v0.7.3 已上 npm,但它的两个流水线问题和两处诚实性问题是在 tag 之后才修的,这一版把它们发出去。
|
|
@@ -16,6 +16,30 @@
|
|
|
16
16
|
- 默认禁止 eda_auto_layout / eda_auto_route(需 force:true 且设置里放行)。
|
|
17
17
|
版面检查用「导出图片自行识别」,不要让 EDA 自动重排。
|
|
18
18
|
|
|
19
|
+
## 0. 开工前:参数没问清就不要动手
|
|
20
|
+
|
|
21
|
+
"帮我画一块 X 板"不是规格。供电、接口、板框、层数、连接器朝向这些一旦猜错,板子可能电气正确但完全用不了(外部横评里 6 个模型全都在结果上翻车,多数不是画错线而是没问清前提)。
|
|
22
|
+
|
|
23
|
+
**第一动作**:调 `eda_design_intake`,拿到 6 个部分 22 个问题(其中 14 个 critical)。
|
|
24
|
+
|
|
25
|
+
| 部分 | critical 问题 |
|
|
26
|
+
|---|---|
|
|
27
|
+
| 供电与电流 | 电源来源、输入电压/电流、需要的电源轨 |
|
|
28
|
+
| 主控与固件 | 主控型号、时钟方案、烧写接口 |
|
|
29
|
+
| 接口与外设 | 对外接口清单、是否隔离/高压 |
|
|
30
|
+
| 机械与结构 | 板框尺寸形状、定位孔、连接器朝向 |
|
|
31
|
+
| 工艺与制造 | 层数、贴片方式 |
|
|
32
|
+
| 交付与验证 | 交付到什么程度(原理图/PCB/可下单) |
|
|
33
|
+
|
|
34
|
+
**怎么做**:
|
|
35
|
+
|
|
36
|
+
1. critical 项用 `ask_user_question` 一次问清(有 options 的直接给选项),**不要编造默认值当作已知**;
|
|
37
|
+
2. non-critical 项在用户没意见时用工具给的 fallback,并在回复里明说"按默认值处理";
|
|
38
|
+
3. 拿到答复后用 `eda_design_intake({answers:{...}})` 记录,`ready:true` 才算参数齐全;
|
|
39
|
+
4. 参数齐了再开始摆器件;未记录参数时第一次 `eda_place_component` 会返回 `intakeWarning`(不阻断,但会点名缺哪些项)。
|
|
40
|
+
|
|
41
|
+
**反模式**(都真实发生过):先摆一堆器件再问;把"最小系统板"当成"STM32+USB+晶振"直接开工;板框随手 60×40 导致连接器装不进外壳;默认 2 层却要求阻抗控制。
|
|
42
|
+
|
|
19
43
|
## 1. 项目层:列出 / 打开 / 新建 / 保存 / 导出
|
|
20
44
|
|
|
21
45
|
- 列工程:eda_list_projects。无过滤时遍历所有本地目录聚合,字段 friendlyName / teamUuid / uuid。
|
|
@@ -122,6 +146,101 @@
|
|
|
122
146
|
| eda_launch 带 project 没打开工程 | 命令行路径被应用忽略 | 用 eda_open_project({ name }) 打开 |
|
|
123
147
|
| 关应用后改动丢失 | eda_close 走了强制路径 | 关前先保存;看返回的 forced |
|
|
124
148
|
| run_code 读大 JSON 被截断 | 宿主 read 有单行上限 | 用 node:fs 读盘或分片读 |
|
|
149
|
+
| 覆铜创建失败(无法创建覆铜边框图元) | 应用侧限制:polygonStage=ok(轮廓被接受)但 pours 被拒,与网络/填充方式/坐标无关 | 工具会重试一次并给出该诊断;手工在 PCB 页框选覆铜(GND,顶层+底层),design_audit 记为 warn |
|
|
150
|
+
| pcb_draw_mounting_hole 报“无法创建焊盘图元” | pad 形状必填,且槽孔只能用 ELLIPSE | 已内建:圆孔 ELLIPSE(d,d),槽孔 ELLIPSE(长,宽)+hole[SLOT,宽,长];OBLONG/RECTANGLE 焊盘会被拒 |
|
|
151
|
+
| pcb_PrimitiveString.getAll / pcb_PrimitivePad.getAll 返回 0 | 这两个 API 按层查询 | 传 layer:丝印 3/4,多层焊盘 12;不传参恒为 0 |
|
|
152
|
+
| 按坐标算的越界没被发现 | 图框/原点假设与真实页面不一致 | 用 eda_get_page_info 的真实值 + eda_capture 导 PNG 看实际版面 |
|
|
153
|
+
| dmt_Project.* / 任意方法报 not allowed | 装的是旧扩展;或旧桥接用本地副本误拦 | eda_list_api_methods 看 source:extension 的真实清单;桥接已不再预拦,直接调用让扩展裁决 |
|
|
154
|
+
- 能力边界以**扩展自报**为准:eda_list_api_methods 的 source 为 extension 时是运行中扩展的真实白名单(含 fileCount);bridge-local-copy 仅表示装的是旧 zip。eda_api_call 不再用桥接本地副本预拦,未知方法直接转发并由扩展裁决。
|
|
155
|
+
|
|
156
|
+
## 9b. PCB 设计与工艺规则(真机踩出来的)
|
|
157
|
+
|
|
158
|
+
- 布线顺序:先信号线 → 再电源线(按角色线宽)→ 最后打 GND 缝合孔 → 铺 GND 铜。反序会让铜把信号围死。
|
|
159
|
+
- 板框:圆角/倒角用 pcb_draw_polyline 折线近似;定位孔与槽口用 pcb_draw_mounting_hole(非金属化 ROUND/SLOT),不要靠挖板框制造孔。
|
|
160
|
+
- 丝印层放信息:pcb_draw_text 写引脚功能、接口名、版号、制版信息;丝印不得压焊盘。
|
|
161
|
+
- 元件方向:连接器/USB/DC 座插口朝板边,IC 的 pin1 统一朝向,极性元件(电解、二极管、LED)方向一致;镜像前先核对引脚顺序。
|
|
162
|
+
- 晶振:紧贴 MCU 时钟脚,负载电容就近,时钟走线短且等长;晶振下方用 pcb_create_region(ruleType:7 noPours) 禁铺铜。无晶振的板跳过。
|
|
163
|
+
- 地:信号地与功率地在单点用 0Ω 电阻(或磁珠)连接,电源层级差大时必做;铺铜按地类型分区。
|
|
164
|
+
- 未使用引脚:原理图用 eda_set_no_connect 打未连接标记,不要留悬空。
|
|
165
|
+
- 位置不能只靠算:eda_get_page_info 取真实图框,eda_capture 导 PNG 看实际版面与越界。
|
|
166
|
+
| PCB 坐标“算不准/越界判错” | EDA 界面显示画布坐标,API 用数据坐标,二者有偏移 | eda_pcb_canvas_origin 查偏移;align:true 调 setCanvasOrigin(0,0) 让两者一致 |
|
|
167
|
+
| 场景 | 是否截图 | 看什么 |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| 布局完成、待布线 | **必须** | 器件越界/互相压住、连接器朝向、安装孔与器件冲突 |
|
|
170
|
+
| 布线完成、待 DRC | **必须** | 跨网络贴合、天线 stub、绕远长线、GND 孤岛 |
|
|
171
|
+
| 丝印/工艺文字放完 | **必须** | 压焊盘、被板边裁切、方向反了(原理图看标签重叠、框线穿器件) |
|
|
172
|
+
| 坐标结果与直觉冲突 | **必须** | 图是唯一裁决者,别和算术争 |
|
|
173
|
+
| 每改一个图元 | 不要 | 单次约 2.7 s / 0.4 MB,还会挤占上下文;批量改完再截 |
|
|
174
|
+
| 确认返回值/属性 | 不要 | 用 eda_get_* 读数据,比图准 |
|
|
175
|
+
| DRC 已给 primitiveId | 不要 | 直接定位 |
|
|
176
|
+
|
|
177
|
+
- **看图要顺手清理**:`eda_capture` 的 PNG 是临时文件 —— 读完立刻 `eda_capture({cleanup:true})`,它只删本会话自己写过的路径;不要在磁盘上留截图。
|
|
178
|
+
|
|
179
|
+
## 9c. 外部对照:AI 画板已知失败模式(来自公开基准与实测)
|
|
180
|
+
|
|
181
|
+
来源:HWE-Bench(arXiv 2603.18102,300 个板级任务 + 2914 份数据手册,结论是硬件零容错、必须执行驱动验证而非文本比对);6 个模型通过 MCP 在嘉立创 EDA 里画 STM32 核心板的横评(DRC 干净但 MCU 电源脚接错;USBLC6 地未连、D+ 缺 1.5k 上拉、CH340G 缺 12MHz、Type-C 只接一个方向、去耦不足);KiCad sch-api issue #104(LLM 放标签“靠近但不在导线上”,根因是缺摆放指引/栅格对齐/引脚坐标数学)。
|
|
182
|
+
|
|
183
|
+
本插件对应的做法:标签一律引脚派生(*_at_pin)、批量放置、跨区域用网络端口;DRC 只当辅助信号,真正的电气判定交给 `eda_netlist_erc`。
|
|
184
|
+
|
|
185
|
+
### eda_netlist_erc:网表级电气烟雾测试(只读,不依赖应用 DRC)
|
|
186
|
+
|
|
187
|
+
| 检查 | 判据 |
|
|
188
|
+
|---|---|
|
|
189
|
+
| duplicate-designator | 位号重复 → fail |
|
|
190
|
+
| unconnected-pin | 引脚不在任何网络 → warn(未用脚请打 no-connect) |
|
|
191
|
+
| dangling-net | 网络只有 1 个端点 → fail |
|
|
192
|
+
| ground-net | 无 GND/VSS/AGND → fail;端点 < 3 → warn |
|
|
193
|
+
| shorted-component | 某器件所有脚在同一网络(如串阻两端同名)→ fail |
|
|
194
|
+
| power-rail | IC 电源脚(VDD/VCC/VBAT/VDDA…)悬空 → fail |
|
|
195
|
+
| decoupling | 某条电源轨没有任何电容到地 → warn |
|
|
196
|
+
| usb-data-pair | 只有 D+ 或只有 D- → fail |
|
|
197
|
+
| crystal | 晶振两脚同网、缺负载电容、或不通向 MCU → warn |
|
|
198
|
+
| reset | NRST 缺电容或电阻 → warn |
|
|
199
|
+
| boot | BOOT0 无下拉/上拉电阻 → warn |
|
|
200
|
+
| type-c-cc | CC1/CC2 缺 5.1k 下拉 → warn |
|
|
201
|
+
|
|
202
|
+
用法:布线/投板前跑一次 `eda_netlist_erc`,`includeOk:true` 看全量;这不是仿真,不能替代 DRC 与人工复核。
|
|
203
|
+
|
|
204
|
+
### 参考基线:拿官方示例工程当尺子(本地实测,非传闻)
|
|
205
|
+
|
|
206
|
+
`D:\文档\LCEDA-Pro\example-projects\示例工程_*.eprj2` 是随安装包分发的官方工程,可以直接打开量。实测 `示例工程_快速入门`:
|
|
207
|
+
|
|
208
|
+
| 指标 | 官方示例 | 本机 STM32 板 | 结论 |
|
|
209
|
+
|---|---|---|---|
|
|
210
|
+
| 板框 | 2362×3150 mil | 2400×1400 mil | 尺寸不同,不可比 |
|
|
211
|
+
| 走线数 / 线宽 | 98 条,**15 mil(67) + 25 mil(31)** | 502 条,6–16 mil | 官方示例没有 6 mil 细线:**15 mil 才是它的常规信号宽度** |
|
|
212
|
+
| 过孔 | 0(示例板未用) | 52 | 视密度而定 |
|
|
213
|
+
| 覆铜 | **1** | **0** | 官方示例确实铺铜 |
|
|
214
|
+
| 丝印文本图元 | **19** | **0** | 差距最大的一项:官方示例写了 19 段丝印说明 |
|
|
215
|
+
| design_audit | **0 违规 / 0 警告** | 0 违规 / 4 警告(5V 线宽偏细、无覆铜、无丝印、无定位孔) | 规则已用参考设计校准 |
|
|
216
|
+
|
|
217
|
+
**建立基线的过程本身修掉了我两条误报**(这是对照的直接收益):
|
|
218
|
+
|
|
219
|
+
1. `$1N6954` 这类 EDA 自生成的隐藏电源网络名被我的字符集规则判为非法 → 现在放行 `$` 开头的自动名;
|
|
220
|
+
2. 15 mil 被我的“0.05 mm 步进”规则报警 → 15/25/12 mil 视为标准档位;另有 9.81 mil 的舍入噪声(0.2492 mm)改为按“距最近 0.05 mm 档 0.01 mm 容差”判断。
|
|
221
|
+
|
|
222
|
+
### 其它权威来源(读它就能画得更准)
|
|
223
|
+
|
|
224
|
+
| 来源 | 提供什么 |
|
|
225
|
+
|---|---|
|
|
226
|
+
| ST **AN4488 / AN2586**(STM32 硬件设计指南) | 去耦电容取值与摆位、晶振负载电容与地平面、BOOT0/NRST 上拉、VDD/VDDA 分离 |
|
|
227
|
+
| USB-IF / TI USB Type-C 参考设计(tiduc55) | CC1/CC2 各 5.1k 下拉、D+/D- 90Ω 差分、ESD 器件接地回路、双方向接法 |
|
|
228
|
+
| IPC-2221 / IPC-7351 | 走线间距与载流、焊盘与丝印外扩、孔环要求 |
|
|
229
|
+
| 官方 `easyeda/extension-dev-skill` 38 份配方 + `easyeda-pro-file-format-v2` | API 正确用法与文件格式(本插件已全面对照,见第 9 章末) |
|
|
230
|
+
|
|
231
|
+
用法:新板开工前先把 `example-projects` 里最接近的一块打开,`eda_design_audit` + `eda_capture` 各跑一次,把它的走线宽度分布、覆铜、丝印量当作自己的下限。
|
|
232
|
+
|
|
233
|
+
## 9d. 验证与交付:三件套把"做完了"变成证据
|
|
234
|
+
|
|
235
|
+
| 工具 | 检查什么 | 什么时候跑 |
|
|
236
|
+
|---|---|---|
|
|
237
|
+
| `eda_schematic_audit` | 原理图**几何**:符号出框、压标题栏、符号互相压住、偏离 10 单位栅格、标签落进符号体 | 布局完成后 |
|
|
238
|
+
| `eda_netlist_erc` | **电气**:位号重复、悬空脚、单端点网络、器件全脚同网、电源脚悬空、缺去耦、USB D± 不成对、晶振缺负载电容、复位/BOOT 缺上下拉、Type-C CC 缺下拉、**缺料号**、**Convert to PCB = no**、**缺封装** | 布线前、投板前 |
|
|
239
|
+
| `eda_delivery_checklist` | 一次串完 ERC + PCB 审计/DRC + Gerber + BOM,逐步 PASS/FAIL;`outPath` 落 Markdown 报告 | 交付前,代替"我说做完了" |
|
|
240
|
+
|
|
241
|
+
**交付口径**:`eda_delivery_checklist` 返回 `ok:true` 才算可以下单;任何一步 FAIL 都要先修,不许口头绕过。报告里带时间戳与计数,可直接给人复核。
|
|
242
|
+
|
|
243
|
+
**参数持久化**:`eda_design_intake({answers})` 会把答复写进**工程描述**(`[dsh-eda-spec] {...}`),下次会话调用 `eda_design_intake` 会自动读回,不用重新猜;`reset:true` 清空。
|
|
125
244
|
|
|
126
245
|
## 10. 端到端剧本
|
|
127
246
|
|
package/docs/tools.md
CHANGED
|
@@ -52,8 +52,14 @@ Design limits enforced by these tools (track widths, via sizes, net naming) are
|
|
|
52
52
|
| `eda_get_active_document` | Return the document/tab that is currently active (documentType, uuid, tabId, parent project). Most tab-dependent APIs (sch_Net.*, netlist export, DRC) only work when the matching document is active - use eda_open_document to switch. | `` |
|
|
53
53
|
| `eda_open_document` | Open/activate a document tab by uuid (dmt_EditorControl.openDocument). Works for a schematic page or a PCB, so tab-dependent APIs can run. | `documentUuid: string, splitScreenId?: string` |
|
|
54
54
|
| `eda_get_net_labels` | List every label-like primitive on the active schematic page: attribute primitives (netlabel/netport/netflag) PLUS plain texts left by the createNetLabel fallback, so they can be audited and deleted. Reports kind/primitiveId/net per entry. | `parentPrimitiveId?: string` |
|
|
55
|
+
| `eda_schematic_audit` | Geometry audit of the active schematic page (the netlist ERC only judges connectivity): symbols outside the frame, symbols overlapping the title block, body-on-body symbol overlap, off-grid placement, and labels anchored inside a symbol body. Read-only; pair it with eda_netlist_erc before routing. | `grid?: number, includeOk?: boolean` |
|
|
56
|
+
| `eda_delivery_checklist` | Delivery checklist: run connectivity (eda_netlist_erc), PCB audit + DRC, Gerber export and BOM export in ONE read-only call and report per-step pass/fail with counts. Pass outPath to also write a Markdown report you can hand to a reviewer. Use it instead of claiming a board is finished. | `outPath?: string, pcbDrc?: boolean` |
|
|
57
|
+
| `eda_design_intake` | Requirement intake for a new board: call it BEFORE placing anything when the request is vague (for example: draw me an X board). Without answers it returns the questions in 6 sections (power, core, IO, mechanical, process, delivery), each marked critical or fallback-able with the reason it changes the drawing; pass answers:{questionId:value} to record them and see what is still missing. Ask the user with ask_user_question for the critical ones instead of guessing. | `answers?: object, reset?: boolean` |
|
|
58
|
+
| `eda_netlist_erc` | Read-only electrical smoke test over the schematic NETLIST (no application DRC needed): duplicate designators, unconnected pins, single-endpoint nets, shorted parts, power rails and decoupling, USB D+/D- pair, crystal (two nets + load caps + reaches the MCU), reset RC, BOOT pull resistor, Type-C CC pull-downs. DRC can be clean while the circuit is still wrong; these failures all show up in the netlist. Pass includeOk:true to see passing checks too. | `includeOk?: boolean` |
|
|
59
|
+
| `eda_pcb_canvas_origin` | Read (or align) the PCB canvas origin and convert points between the two coordinate spaces. JLCEDA displays CANVAS coordinates in its UI but every API takes DATA coordinates; the two differ by this offset, so a coordinate read off the screen will land somewhere else unless you convert or align. align:true calls setCanvasOrigin(0,0) so the display matches the API. | `align?: boolean, offsetX?: number, offsetY?: number, point?: object` |
|
|
60
|
+
| `eda_capture` | Render the active document to a PNG (dmt_EditorControl.getCurrentRenderedAreaImage) and write it to outPath or return a data URL. Use it to LOOK at the sheet/board instead of trusting coordinate math. The PNG is a scratch file: read it, then call eda_capture({cleanup:true}) to delete every capture path this session wrote. | `outPath?: string, inline?: boolean, cleanup?: boolean` |
|
|
55
61
|
| `eda_workflow_guide` | Return the schematic working standard: grid-aligned manual placement, signal flow, when net labels/ports are required (a wire net name is overridden by connectivity), net-label fallback behaviour, batch placement and the verification order. Read it before laying out a sheet. | `` |
|
|
56
|
-
| `eda_list_api_methods` |
|
|
62
|
+
| `eda_list_api_methods` | Ask the CONNECTED EXTENSION for the API methods it accepts right now (dsh.internal.listApiMethods) and report source/version/counts. Falls back to the bridge copy with stale:true only when the extension is an older zip. Use refresh:true to re-query. | `refresh?: boolean` |
|
|
57
63
|
|
|
58
64
|
## Schematic: place & draw
|
|
59
65
|
|
|
@@ -70,9 +76,11 @@ Design limits enforced by these tools (track widths, via sizes, net naming) are
|
|
|
70
76
|
| `eda_draw_functional_box` | Draw a dashed functional-group box around one group of components, with an optional label. Margins and coordinates are MCP units; default margin 1 unit (about 0.254 mm). | `componentIds?: array, label?: string, margin?: number, color?: string, lineWidth?: integer, lineType?: integer` |
|
|
71
77
|
| `eda_draw_circle` | Draw a circle. Coordinates are MCP units. | `centerX: number, centerY: number, radius: number, color?: string, fillColor?: string, lineWidth?: integer, lineType?: integer, fillStyle?: string` |
|
|
72
78
|
| `eda_draw_text` | Draw text. Coordinates are MCP units. | `x: number, y: number, content: string, rotation?: integer, textColor?: string, fontName?: string, fontSize?: number, bold?: boolean, italic?: boolean, underLine?: boolean, alignMode?: integer` |
|
|
73
|
-
| `eda_place_net_label` | Place a net label at x/y. The real API (sch_PrimitiveAttribute.createNetLabel) is probed once per session; when the build never answers, a plain TEXT label is placed instead, which carries no electrical meaning and must be paired with a stub wire. Pass probe:true to re-check. | `x: number, y: number, net: string, fontSize?: number, rotation?: integer` |
|
|
74
|
-
| `eda_place_net_labels` | Place many net labels in ONE call (per-pin or by coordinate) and report done/failed per item: a 133-label schematic used to exceed the caller timeout with no progress. items: [{ pinPrimitiveId, net, stubLength?, offsetX?, offsetY? }] or [{ x, y, net, fontSize? }]. | `items: array, probe?: boolean, concurrency?: integer` |
|
|
79
|
+
| `eda_place_net_label` | Place a net label at x/y. The real API (sch_PrimitiveAttribute.createNetLabel) is probed once per session; when the build never answers, a plain TEXT label is placed instead, which carries no electrical meaning and must be paired with a stub wire. Pass probe:true to re-check. | `x: number, y: number, net: string, fontSize?: number, rotation?: integer, probe?: boolean, textLabel?: boolean` |
|
|
80
|
+
| `eda_place_net_labels` | Place many net labels in ONE call (per-pin or by coordinate) and report done/failed per item: a 133-label schematic used to exceed the caller timeout with no progress. items: [{ pinPrimitiveId, net, stubLength?, offsetX?, offsetY? }] or [{ x, y, net, fontSize? }]. | `items: array, probe?: boolean, textLabel?: boolean, concurrency?: integer` |
|
|
75
81
|
| `eda_move_component` | Move/rotate/mirror a schematic component (sch_PrimitiveComponent.modify) without deleting and re-placing it, so the designator and value survive. | `primitiveId: string, x?: number, y?: number, rotation?: number, mirror?: boolean` |
|
|
82
|
+
| `pcb_draw_text` | Put text on a PCB layer - silkscreen by default (3 top silk / 4 bottom silk). Use it for pin functions, board markings, version and fabrication notes; silkscreen text must not cover pads. | `x: number, y: number, text: string, layer?: string, fontSize?: number, lineWidth?: number, rotation?: number, mirror?: boolean, alignMode?: integer, locked?: boolean` |
|
|
83
|
+
| `pcb_draw_mounting_hole` | Place a NON-plated mounting hole or a slot (pcb_PrimitivePad with metallization:false). shape "round" is a drill-sized hole, shape "slot" an oval cut-out. Use this for mounting holes and connector slots instead of hacking the board outline. | `x: number, y: number, diameter: number, shape?: string, slotLength?: number, rotation?: number, plated?: boolean, annulus?: number, padNumber?: string, layer?: string` |
|
|
76
84
|
| `eda_delete_primitive` | Delete a schematic primitive by kind and primitive id. Net ports, net flags and net labels are attribute primitives and need kind "netport"/"netflag"/"netlabel"; the text fallback labels are kind "text". | `kind: string, primitiveId: string` |
|
|
77
85
|
|
|
78
86
|
## Schematic: automation & export
|
|
Binary file
|
|
@@ -171,6 +171,9 @@ function dshEdaMcpStatus() {
|
|
|
171
171
|
'pcb_Document.navigateToCoordinates',
|
|
172
172
|
'pcb_Document.zoomToBoardOutline',
|
|
173
173
|
'pcb_Document.getCanvasOrigin',
|
|
174
|
+
'pcb_Document.setCanvasOrigin',
|
|
175
|
+
'pcb_Document.convertCanvasOriginToDataOrigin',
|
|
176
|
+
'pcb_Document.convertDataOriginToCanvasOrigin',
|
|
174
177
|
'pcb_Primitive.getPrimitivesBBox',
|
|
175
178
|
'pcb_PrimitiveComponent.create',
|
|
176
179
|
'pcb_PrimitiveComponent.getAll',
|
|
@@ -200,6 +203,15 @@ function dshEdaMcpStatus() {
|
|
|
200
203
|
'pcb_PrimitiveRegion.modify',
|
|
201
204
|
'pcb_PrimitiveRegion.delete',
|
|
202
205
|
'pcb_MathPolygon.createPolygon',
|
|
206
|
+
'pcb_MathPolygon.createComplexPolygon',
|
|
207
|
+
'pcb_PrimitiveString.create',
|
|
208
|
+
'pcb_PrimitiveString.get',
|
|
209
|
+
'pcb_PrimitiveString.getAll',
|
|
210
|
+
'pcb_PrimitiveString.modify',
|
|
211
|
+
'pcb_PrimitiveString.delete',
|
|
212
|
+
'pcb_PrimitivePad.create',
|
|
213
|
+
'pcb_PrimitivePad.getAll',
|
|
214
|
+
'pcb_PrimitivePad.delete',
|
|
203
215
|
'pcb_PrimitivePour.create',
|
|
204
216
|
'pcb_PrimitivePour.modify',
|
|
205
217
|
'pcb_PrimitivePour.delete',
|
|
@@ -385,6 +397,17 @@ function dshEdaMcpStatus() {
|
|
|
385
397
|
return { result: impResult === undefined ? null : toJsonable(impResult) };
|
|
386
398
|
}
|
|
387
399
|
// Internal helper: build an IPCB_Polygon from a raw source array and create
|
|
400
|
+
// Internal helper: report THIS extension's own allow-list. The bridge keeps a
|
|
401
|
+
// copy for docs/offline hints, but it drifts — and a bridge that is stricter
|
|
402
|
+
// than the extension silently rejects methods that actually work. This is the
|
|
403
|
+
// authority: what the running extension will accept right now.
|
|
404
|
+
if (message.method === 'dsh.internal.listApiMethods') {
|
|
405
|
+
return {
|
|
406
|
+
version: VERSION,
|
|
407
|
+
allowed: Array.from(ALLOWED_API).sort(),
|
|
408
|
+
files: Array.from(FILE_METHODS).sort(),
|
|
409
|
+
};
|
|
410
|
+
}
|
|
388
411
|
// a PCB region (used for the board outline).
|
|
389
412
|
if (message.method === 'dsh.internal.pcbCreateRegion') {
|
|
390
413
|
var regionArgs = message.args || [];
|
|
@@ -428,8 +451,14 @@ function dshEdaMcpStatus() {
|
|
|
428
451
|
if (typeof eda === 'undefined' || !eda.pcb_MathPolygon || !eda.pcb_PrimitivePour) {
|
|
429
452
|
throw new Error('dsh.internal.pourCreate: PCB pour APIs are not available');
|
|
430
453
|
}
|
|
431
|
-
|
|
432
|
-
|
|
454
|
+
// A pour is a complex polygon (an outer ring plus optional holes). Passing a
|
|
455
|
+
// single IPCB_Polygon made the app answer 无法创建覆铜边框图元; createComplexPolygon is the documented entry point.
|
|
456
|
+
var pourSource = pourArgs[2];
|
|
457
|
+
var pourPolygon = eda.pcb_MathPolygon.createComplexPolygon
|
|
458
|
+
? eda.pcb_MathPolygon.createComplexPolygon(Array.isArray(pourSource) && Array.isArray(pourSource[0]) ? pourSource : [pourSource])
|
|
459
|
+
: undefined;
|
|
460
|
+
if (!pourPolygon) pourPolygon = eda.pcb_MathPolygon.createPolygon(pourSource);
|
|
461
|
+
if (!pourPolygon) throw new Error('dsh.internal.pourCreate: invalid polygon source ' + JSON.stringify(pourSource));
|
|
433
462
|
var pour = await eda.pcb_PrimitivePour.create(
|
|
434
463
|
optional(pourArgs[0]), optional(pourArgs[1]), pourPolygon, optional(pourArgs[3]), optional(pourArgs[4]),
|
|
435
464
|
optional(pourArgs[5]), optional(pourArgs[6]), optional(pourArgs[7]), optional(pourArgs[8])
|
|
@@ -437,7 +466,15 @@ function dshEdaMcpStatus() {
|
|
|
437
466
|
if (!pour) {
|
|
438
467
|
throw new Error('dsh.internal.pourCreate: pcb_PrimitivePour.create returned undefined (net/layer/polygon rejected; copper layers only)');
|
|
439
468
|
}
|
|
440
|
-
|
|
469
|
+
// A pour border alone leaves no copper: the region has to be rebuilt for the
|
|
470
|
+
// fill (and the clearance against other nets) to be computed.
|
|
471
|
+
var rebuilt = false;
|
|
472
|
+
if (pour && typeof pour.rebuildCopperRegion === 'function') {
|
|
473
|
+
try { await pour.rebuildCopperRegion(); rebuilt = true; } catch (error) { rebuilt = false; }
|
|
474
|
+
}
|
|
475
|
+
var pourJson = toJsonable(pour);
|
|
476
|
+
if (pourJson && typeof pourJson === 'object') pourJson.rebuilt = rebuilt;
|
|
477
|
+
return pourJson;
|
|
441
478
|
}
|
|
442
479
|
// Internal helper: long-running jobs (auto-routing / auto-layout) are started
|
|
443
480
|
// without awaiting so the MCP call returns immediately; the operation keeps
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"uuid": "d5e0a1b2c3f4456789abcdef01234567",
|
|
3
3
|
"name": "dsh-eda-bridge",
|
|
4
4
|
"displayName": "DSH EDA MCP Bridge",
|
|
5
|
-
"version": "0.4.
|
|
5
|
+
"version": "0.4.6",
|
|
6
6
|
"description": "Local WebSocket bridge used by the dsh-eda-mcp plugin to let DeepSeek Harness draw schematics and drive PCB operations in JLCEDA Pro through the official extension API.",
|
|
7
7
|
"entry": "./api-bridge.js",
|
|
8
8
|
"publisher": "dsh-eda-mcp",
|