dsh-eda-mcp 0.7.0 → 0.7.2

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 CHANGED
@@ -1,5 +1,95 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.2 — 2026-10-20
4
+
5
+ 本版把原理图批量落地的 15 个问题全部处理完(13 修、2 记为限制),并把工作规范正式注册成 DSH 技能、扩成完整项目手册。
6
+
7
+ ### 技能内容补全:从「原理图规范」升级为「项目全流程手册」
8
+
9
+ 技能正文从 2513 字符扩到 **9262 字符 / 12 章 / 149 行**,覆盖一个嘉立创项目从打开到出 Gerber 的完整链路:
10
+
11
+ | 章 | 内容 |
12
+ |---|---|
13
+ | 0 | 适用范围与硬前提(坐标/单位/图框、活动文档语义、版本一致性、禁止自动布局) |
14
+ | 1 | 项目层:列出 / 按名打开 / **导入即新建** / 保存 / 导出,以及本构建不可用项与替代 |
15
+ | 2 | 原理图读取顺序(活动文档 → 页信息 → 器件包围盒 → 引脚一次拿全 → 连线/网络/标签 → 工程结构) |
16
+ | 3 | 布局规范(10 单位栅格、信号左→右、电源上/地下、间距、功能框、挪件保标注、导出图片自查) |
17
+ | 4 | 连线与网络(wire 语义、跨区域必须用端口/标签、标签降级与 stub、`*_at_pin`、差分对命名、未连接标记、删除 kind) |
18
+ | 5 | 批量与超时控制(`eda_place_net_labels`、≤20/批、进度锚点、探测结果按会话缓存) |
19
+ | 6 | 原理图校验(网表端点、DRC 明细、BOM 解码、命名比对) |
20
+ | 7 | PCB 全流程(同步与对话框、读层/网络/焊盘、板框、布局、走线/过孔/铺铜、自动布线策略、DRC+审计、Gerber) |
21
+ | 8 | 设计规则速查(网络名、线宽档位、过孔尺寸、铺铜间距、丝印) |
22
+ | 9 | **故障与处置表**:14 类现象 → 原因 → 动作(未连接、版本不匹配、白名单拒绝、60s 超时、空返回、createNetLabel 不响应、标签查不到、导线 net 被改、重叠、导入 uuid 冲突、工程 API 无效、命令行被忽略、强制关闭丢改动、read 截断) |
23
+ | 10 | 三段端到端剧本(改已有原理图 / 新建工程出板 / 只做 PCB) |
24
+ | 11 | 交付前 8 项检查清单 |
25
+
26
+ 配套改动:`src/skills-content.ts` 成为**唯一内容源**(技能正文 + 系统提示精简版 + 文档都由它派生);新增 `scripts/gen-skill-doc.mjs` 生成 `docs/schematic-workflow.md`(并入 `pnpm docs`),杜绝文档与技能漂移;`test/skills.test.ts` 扩到 **37 条断言**(12 章齐全、正文 >6000 字符、14 个关键工具名、故障表头)。
27
+ ### 技能(skill)正式注册 + 自动布局拒绝后的引导
28
+
29
+ - **技能通过 `ctx.skills.registerProvider()` 注册**(不是只有系统提示):新增 `src/skills.ts`,提供 `jlceda-schematic-workflow` 技能(kebab-case、rank 500 优先于用户根 400、`TRIGGER when` / `DO NOT TRIGGER` 齐全,正文 2513 字符 = 布局规范 + 网络/标签规则 + 批量与超时 + 失败先看返回值)。宿主没有 skills 服务时(旧版本)自动跳过,不报错。
30
+ - 新增 `test/skills.test.ts`(11 条断言:provider 名、单一技能、kebab-case、可被模型/用户调用、trigger 文案、rank、正文长度与关键段落、未知技能返回 undefined),已加入 `pnpm test`。
31
+ - **`eda_auto_layout` / `eda_auto_route` 的拒绝消息改成可执行的引导**:不再只说"被禁用",而是列出 7 步替代流程(确认活动原理图 → 读图框安全区 → 盘已有器件 → 10 单位栅格 `eda_place_component`/`eda_move_component` → `eda_draw_wire` 局部连线 + 跨区域用网络端口/标签 → `eda_export_netlist` + `eda_run_drc` 校验并导出图片自查 → `eda_workflow_guide`),并明确"除非用户明确要求,不要用 force:true 重试"。
32
+
33
+ 注:技能注册在**宿主重启**后生效(插件重新加载),桥接 reconnect 不够。
34
+ ### 原理图批量落地暴露的 15 个问题:修了 13 个,2 个只能记为限制
35
+
36
+ 全部来自一次真实的 45 网络原理图绘制(EDA 3.2.186、已登录、半离线)。**本轮没有改动扩展白名单,线协议仍是 0.4.0,已装扩展无需重导。**
37
+
38
+ #### 网络标签 / 可用性(影响最大的三项)
39
+
40
+ - **createNetLabel 探测不再每次都付 4 秒**:探测结论按**会话缓存**(`netLabelSupport`),首次失败后直接走文本降级;`probe:true` 可强制重测。133 个标签从 ≈15 分钟降到一次批量调用。
41
+ - **新增 `eda_place_net_labels([…])`**:一次 MCP 调用放多枚标签(按引脚或坐标),逐条返回 `ok/error` 并给出 `done/failed/total`,不再"超时前无进度、只能重来推断"。
42
+ - **`eda_get_net_labels` 现在真能列出标签**:同时枚举 `sch_PrimitiveAttribute.getAll`(netlabel/netport/netflag)与 `sch_PrimitiveText.getAll`(文本降级标签),并报告 `attributeCount/textCount/sessionTextLabels`;之前放置后仍 `count:0`。
43
+
44
+ #### 静默失败与不可审计图元
45
+
46
+ - **`eda_copy_project` 不再静默**:底层返回值原样透出(`raw`),异常包装成可读错误,`copied:false` 时给 `hint`(该构建对本地工程无效,建议应用内复制或导出+导入生成独立副本)。
47
+ - **`eda_delete_primitive` 支持 `netport` / `netflag` / `netlabel`**(走 `sch_PrimitiveAttribute.delete`):网络端口不再只能靠记住放置时的 id 才能删。
48
+ - **新增 `eda_move_component`**(`sch_PrimitiveComponent.modify`):原理图挪器件不必删除重放,designator/value 不丢。
49
+
50
+ #### 往返次数与返回值规范
51
+
52
+ - **`eda_get_pins` 一次返回 `pinName`/`pinNumber`**(`getAllPinsByPrimitiveId` 的完整记录,不再被 `summarizePrimitive` 削掉):20 器件 135 引脚从 135 次额外往返降到 20 次。
53
+ - **`eda_run_drc` 返回逐条明细**:改用 `includeVerboseError:true`,给出 `type/message/primitiveId/x/y` 加原始记录;之前只有 `[{type:"warn",count:4}]`。
54
+ - **`eda_export_netlist` 单层结构**:结果是已解析对象(`{parsed:true, netlist}`),不再需要二次 `JSON.parse`;`format:"text"` 保留原始字符串。
55
+ - **`eda_export_bom` CSV 解码 UTF-16LE**:不再出现 `N\u0000o\u0000.` 这种不可读文本。
56
+ - **`eda_open_project` / `eda_import_project` 的 `opened` 可信了**:改为轮询 `getCurrentProjectInfo` 直到 uuid 匹配(默认 4 秒),同时保留 `openReturned` 反映 API 原始布尔;首次返回 false 但实际已切换的问题不再误导调用方。
57
+
58
+ #### 自动布局/布线策略(按你的要求)
59
+
60
+ - **默认禁止**:`eda_auto_layout` / `eda_auto_route` 现在需要 `force:true` **且**设置里开启「允许原理图自动布局/自动布线」(新配置项 `allowAutoLayoutRouting`,默认关;环境变量 `DSH_EDA_ALLOW_AUTO_LAYOUT`)。
61
+ - 新增 `eda_workflow_guide` 工具与 `docs/schematic-workflow.md`:栅格对齐、信号流向、跨区域走网络端口、版面用导出图片核对;系统提示同步加了 4 条规范(含"同名导线不成立"的实测结论)。
62
+
63
+ #### 其他
64
+
65
+ - `eda_zoom_to_fit` 返回的越界 bounds 现在**按图框裁剪**并重新应用(之前 `left:-340 / bottom:-772.9`)。
66
+ - `eda_api_call` 报 `API method not allowed` 时给出白名单规模与指引;新增 **`eda_list_api_methods`** 直接列出全部 166 条方法。
67
+ - `eda_import_project` 增加 **uuid 碰撞检查**:导入后对比其它工程的 internal ids(schematic/page/pcb),在 `collisions` 里报告(`checkCollisions:false` 关闭)。
68
+
69
+ #### 只能记为限制(无法在插件内修复)
70
+
71
+ - **原理图元件与网络端口不在 `eda_get_components` / BOM / 网表里**:属应用行为。已提供 `eda_get_net_labels` 枚举 + `kind:"netport"` 删除来替代审计。
72
+ - **导入 `.epro2` 不重生成内部 uuid**:属应用导入实现。插件只能检测并告警(见上)。
73
+
74
+ #### 附录(已写进工具说明与文档)
75
+
76
+ - `eda_draw_wire` 的 `net` 只对**悬空导线**有效:端点一旦接触引脚,EDA 会按连通性重算网络名(实测 `TESTNET` 并入 `LED_A`);跨区域同名网络必须用网络端口/网络标签。
77
+
78
+ ## 0.7.1 — 2026-10-20
79
+
80
+ 构建产物修正:**扩展 zip 只保留带版本号的那一个**。
81
+
82
+ - 0.7.0 里为了不打破旧引用,同时产出了 `dsh-eda-bridge-extension-0.4.0.zip` 和同内容的 `dsh-eda-bridge-extension.zip`(SHA256 完全一致)。两个同内容文件摆在一起只会让人分不清哪份是当前版本,属于多余的冗余,删掉。
83
+ - 现在只生成 `dsh-eda-bridge-extension-<线协议版本>.zip`。所有引用改为**按版本解析**:
84
+ - `src/index.ts`:从 `jlc-extension/extension.json` 读版本号拼出文件名(找不到时回退旧的固定名,兼容旧布局);
85
+ - `src/routes.ts`:下载响应头用实际文件名的 `basename`,浏览器另存下来自带版本号;
86
+ - 设置卡片的下载链接去掉固定的 `download` 属性,改由响应头决定文件名;
87
+ - 桥接里所有提示语改成 `dsh-eda-bridge-extension-' + VERSION + '.zip`;
88
+ - README(中/英)、CONTRIBUTING、`docs/release.md`、扩展头部注释同步。
89
+ - `package.json files` 去掉固定名条目,只保留 `dsh-eda-bridge-extension-*.zip`。
90
+
91
+ 线协议仍是 **0.4.0**,扩展内容未变——已导入 0.4.0 的机器**无需重新导入**。
92
+
3
93
  ## 0.7.0 — 2026-10-20
4
94
 
5
95
  主题:把「操作嘉立创EDA」从**画图**扩展到**应用与工程**层面,并把这一路真机联调暴露的 bug 全部修掉。
package/CONTRIBUTING.md CHANGED
@@ -34,7 +34,6 @@ pnpm install
34
34
  pnpm typecheck # tsc --noEmit
35
35
  pnpm test # unit tests + the seam compatibility test
36
36
  pnpm build # lib/*.js, lib/bridge.mjs, lib/client.js, dsh-eda-bridge-extension-<version>.zip
37
- # (+ dsh-eda-bridge-extension.zip as a stable-name alias of the same build)
38
37
  pnpm check # all three, in that order
39
38
  pnpm docs # regenerate docs/tools.md from the built bridge
40
39
  pnpm seam-check # assert the plugin's DSH contracts against another version line
package/README.md CHANGED
@@ -16,7 +16,7 @@ DSH agent
16
16
  └─ mcp__jlceda__eda_* tools
17
17
  └─ @deepseek-ai/dsh-mcp-client (stdio)
18
18
  └─ lib/bridge.mjs (local MCP + WebSocket server, 127.0.0.1:39009)
19
- └─ JLCEDA Pro extension dsh-eda-bridge-extension.zip
19
+ └─ JLCEDA Pro extension dsh-eda-bridge-extension-<version>.zip
20
20
  └─ official EasyEDA Pro extension API (eda.sch_*)
21
21
  ```
22
22
 
@@ -36,9 +36,9 @@ pnpm add dsh-eda-mcp # or use the plugin manager in the Web GUI
36
36
  # restart DSH
37
37
  ```
38
38
 
39
- The published package already contains `lib/` and `dsh-eda-bridge-extension.zip`, so no build
39
+ The published package already contains `lib/` and `dsh-eda-bridge-extension-<version>.zip`, so no build
40
40
  toolchain is needed. The extension still has to be imported into JLCEDA Pro by hand — the zip
41
- sits at `node_modules/dsh-eda-mcp/dsh-eda-bridge-extension.zip` (or download it from the
41
+ sits at `node_modules/dsh-eda-mcp/dsh-eda-bridge-extension-<version>.zip` (or download it from the
42
42
  settings card).
43
43
 
44
44
  ### 1. Install into the DSH web profile
@@ -71,10 +71,10 @@ The plugin now resolves a real Node executable (`src/node-runtime.ts`), in order
71
71
 
72
72
  ### 2. Import the JLCEDA Pro bridge extension
73
73
 
74
- Build produces `dsh-eda-bridge-extension-<version>.zip` (plus a `dsh-eda-bridge-extension.zip` alias with identical content; **hand out the versioned file** so stale copies are obvious). In JLCEDA Pro:
74
+ Build produces `dsh-eda-bridge-extension-<version>.zip` only — a second copy under the stable name only made it unclear which build you were looking at. In JLCEDA Pro:
75
75
 
76
76
  1. Open **扩展 → 导入** (Extensions → Import).
77
- 2. Select `dsh-eda-bridge-extension.zip`.
77
+ 2. Select `dsh-eda-bridge-extension-<version>.zip`.
78
78
  3. In the extension list find **DSH EDA MCP Bridge**.
79
79
  4. Enable it and, importantly, enable **允许外部交互 / Allow external interactions**.
80
80
 
@@ -188,7 +188,7 @@ Build outputs:
188
188
  - `lib/index.js` — DSH host plugin.
189
189
  - `lib/client.js` — DSH Web GUI settings card.
190
190
  - `lib/bridge.mjs` — standalone MCP/WebSocket bridge child.
191
- - `dsh-eda-bridge-extension.zip` — JLCEDA Pro extension.
191
+ - `dsh-eda-bridge-extension-<version>.zip` — JLCEDA Pro extension (the version is the wire contract).
192
192
 
193
193
  `lib/` and the zip are build outputs and are git-ignored; the host loads the packaged `lib/index.js`, so a change under `src/` needs `pnpm build` plus a Host restart (a plugin reload does not re-import a cached ESM module).
194
194
 
@@ -215,6 +215,13 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for the repository layout, the release/ta
215
215
  - In semi-offline mode EDA models **each local project directory as a "team"**: the `uuid` reported by `eda_list_teams` is the directory path, while a project record's `teamUuid` is a real uuid. `eda_list_projects` without a filter walks every team, so the first call is slower than one with `teamUuid`.
216
216
  - Spawning `lceda-pro.exe` directly (even through ShellExecute) makes it exit with code 0 immediately; only handing the launch to the desktop shell (`explorer.exe`) starts it, so on Windows `eda_launch` always goes through explorer plus a temporary `.cmd`.
217
217
  - A project path on the command line is **ignored by the app** (the active document stays HOME), so `eda_launch({ project })` only forwards the argument; the result carries `projectOpenedByArgument: false` and a `projectNote`. Use `eda_open_project` to actually open one.
218
+ - Schematic parts move with `eda_move_component` (`sch_PrimitiveComponent.modify`); net ports, net flags, net labels and text labels are deleted with `eda_delete_primitive` kinds `netport` / `netflag` / `netlabel` / `text`.
219
+ - The `net` argument of `eda_draw_wire` only sticks on a **floating** wire: once an endpoint touches a pin, EDA recomputes the net from connectivity (measured: `TESTNET` merged into `LED_A`). Joining same-named nets across regions requires `eda_place_net_port` or a net label.
220
+ - `sch_PrimitiveAttribute.createNetLabel` never resolves on EDA 3.2.186: the probe result is cached per session and placement degrades to a plain text label (no electrical meaning; the stub wire carries the net). Batch with `eda_place_net_labels`, enumerate with `eda_get_net_labels`, clean up with `eda_delete_primitive(kind:"text")`.
221
+ - Net port primitives do not appear in `eda_get_components` / BOM / netlist (application behaviour); audit them through `eda_get_net_labels`.
222
+ - Importing a `.epro2` copies its internal uuids (schematic/page/pcb), which can collide with the source project: `eda_import_project` reports them in `collisions`, but cannot regenerate them.
223
+ - `dmt_Project.copyProject` is as inert as `createProject` / `deleteProject` for local projects; copy with `eda_export_project` + `eda_import_project` instead.
224
+ - Automatic layout/routing is off by default (`allowAutoLayoutRouting`); `eda_auto_layout` / `eda_auto_route` only run with `force:true`.
218
225
  - The extension and bridge wire versions must move **together** (currently 0.4.0): a changed allow-list requires re-importing the zip, otherwise new tools answer `API method not allowed`. `eda_status` reports every connected page's version in `extensionVersions`.
219
226
 
220
227
  ## Repository
package/README.zh.md CHANGED
@@ -16,7 +16,7 @@ DSH Agent
16
16
  └─ mcp__jlceda__eda_* 工具
17
17
  └─ @deepseek-ai/dsh-mcp-client(stdio)
18
18
  └─ lib/bridge.mjs(本地 MCP + WebSocket 服务,127.0.0.1:39009)
19
- └─ 嘉立创EDA专业版扩展 dsh-eda-bridge-extension.zip
19
+ └─ 嘉立创EDA专业版扩展 dsh-eda-bridge-extension-<版本号>.zip
20
20
  └─ 官方扩展 API(eda.sch_*)
21
21
  ```
22
22
 
@@ -47,8 +47,8 @@ pnpm add dsh-eda-mcp # 或用 Web GUI 的插件管理器安装
47
47
  # 重启 DSH
48
48
  ```
49
49
 
50
- 发布包里已包含 `lib/` 与 `dsh-eda-bridge-extension.zip`,**不需要构建工具链**。扩展仍需手动导入
51
- 嘉立创EDA:zip 位于 `node_modules/dsh-eda-mcp/dsh-eda-bridge-extension.zip`(也可从设置卡片下载)。
50
+ 发布包里已包含 `lib/` 与 `dsh-eda-bridge-extension-<线协议版本>.zip`,**不需要构建工具链**。扩展仍需手动导入
51
+ 嘉立创EDA:zip 位于 `node_modules/dsh-eda-mcp/dsh-eda-bridge-extension-<线协议版本>.zip`(也可从设置卡片下载,下载到的文件名自带版本号)。
52
52
 
53
53
  ### 1. 安装到 DSH Web profile
54
54
 
@@ -65,10 +65,10 @@ cd dsh-eda-mcp && pnpm install && dsh plugin --profile web add "link:$PWD"
65
65
 
66
66
  ### 2. 导入嘉立创EDA桥接扩展
67
67
 
68
- 构建会生成 `dsh-eda-bridge-extension-<版本号>.zip`(同时保留 `dsh-eda-bridge-extension.zip` 别名,内容相同;**分发请用带版本号的那个**,方便区分旧副本)。在嘉立创EDA专业版中:
68
+ 构建只生成 `dsh-eda-bridge-extension-<版本号>.zip`(不再保留同名别名——两个同内容文件只会让人分不清是哪一版)。在嘉立创EDA专业版中:
69
69
 
70
70
  1. 打开 **扩展 → 导入**。
71
- 2. 选择 `dsh-eda-bridge-extension.zip`。
71
+ 2. 选择 `dsh-eda-bridge-extension-<版本号>.zip`。
72
72
  3. 在扩展列表中找到 **DSH EDA MCP Bridge**。
73
73
  4. 启用它,并务必开启 **允许外部交互**。
74
74
 
@@ -354,7 +354,7 @@ pnpm check # 以上三步
354
354
  - `lib/index.js` — DSH Host 插件。
355
355
  - `lib/client.js` — DSH Web GUI 设置卡片。
356
356
  - `lib/bridge.mjs` — 独立 MCP/WebSocket 桥接子进程。
357
- - `dsh-eda-bridge-extension.zip` — 嘉立创EDA专业版扩展。
357
+ - `dsh-eda-bridge-extension-<版本号>.zip` — 嘉立创EDA专业版扩展(版本号 = 线协议版本)。
358
358
 
359
359
  `lib/` 与 zip 都是构建产物(已 gitignore);宿主加载的是打包后的 `lib/index.js`,所以改 `src/` 后必须 `pnpm build` **并重启 Host**(插件重载不会重新 import 已缓存的 ESM 模块)。仓库结构、发布打 tag 流程、bridge/扩展版本规则见 [CONTRIBUTING.md](CONTRIBUTING.md);**发布到 npm** 的完整流程(首次手动发布,之后由 `v*` tag 经 trusted publishing/OIDC 自动发布)见 [docs/release.md](docs/release.md)。
360
360
 
@@ -373,6 +373,13 @@ pnpm check # 以上三步
373
373
  - 修改桥接端口需要同时改桥接环境变量和 `jlc-extension/api-bridge.js`,再重新构建并重新导入扩展。
374
374
  - 元件包围盒检查依赖 `sch_Primitive.getPrimitivesBBox`;个别图元若没有 BBox,会跳过超界检查。
375
375
  - 扩展 `activationEvents` 已包含 onStartupFinished / onProjectOpened / onEditorSchematic / onEditorPcb;如果导入旧版扩展后切到 PCB 掉线,请重新导入新版 zip。
376
+ - 原理图元件移动用 `eda_move_component`(`sch_PrimitiveComponent.modify`);网络端口/网络旗标/网络标签/文本标签的删除用 `eda_delete_primitive` 的 `netport` / `netflag` / `netlabel` / `text` 类型。
377
+ - `eda_draw_wire` 的 `net` 只对**悬空导线**有效:端点一旦接触引脚,EDA 会按连通性重算网络名(实测 `TESTNET` 并入 `LED_A`)。跨区域同名网络必须用 `eda_place_net_port` 或网络标签。
378
+ - `sch_PrimitiveAttribute.createNetLabel` 在 EDA 3.2.186 上**永不 resolve**:插件按会话缓存探测结论,之后自动降级为纯文本标签(无电气语义,靠 stub 导线连通网络)。批量请用 `eda_place_net_labels`,标签用 `eda_get_net_labels` 枚举、`eda_delete_primitive(kind:"text")` 清理。
379
+ - 网络端口图元不会出现在 `eda_get_components` / BOM / 网表里(应用行为),只能用 `eda_get_net_labels` 审计。
380
+ - 导入 `.epro2` 会原样复制内部 uuid(schematic/page/pcb),可能与源工程冲突:`eda_import_project` 会检查并在 `collisions` 里报告,但无法重新生成。
381
+ - `dmt_Project.copyProject` 与 `createProject` / `deleteProject` 同样在本地工程上无副作用;复制请用 `eda_export_project` + `eda_import_project`。
382
+ - 自动布局/布线默认关闭(`allowAutoLayoutRouting`),`eda_auto_layout` / `eda_auto_route` 需 `force:true` 才会执行。
376
383
  - `dmt_Project.createProject` / `deleteProject` 在本机 EDA 3.2.186(登录但半离线)上**无副作用**:前者返回空 uuid(目录路径 / 真 team uuid / 带不带 folderUuid 四种组合都试过),后者始终返回 `false`(工程打开时与切走后各试一次)。**新建工程请改用 `eda_import_project`(导入一个工程文件即建出工程,已实测)**,删除请在应用内完成。
377
384
  - 半离线模式下 EDA 把**每个本地工程目录当成一个 "team"**:`eda_list_teams` 返回的 `uuid` 就是目录路径,而工程记录里的 `teamUuid` 是另一种真 uuid。`eda_list_projects` 无过滤时会遍历所有 team 聚合,因此第一次调用会比带 `teamUuid` 时慢一些。
378
385
  - `lceda-pro.exe` 直接 `spawn`(含 ShellExecute)会**立刻以退出码 0 退出**:只有交给桌面外壳(`explorer.exe`)才能起来,所以 `eda_launch` 在 Windows 上固定走 explorer + 临时 `.cmd`。
package/docs/release.md CHANGED
@@ -30,7 +30,7 @@ npm pack --dry-run # 看 tarball 内容
30
30
  ```
31
31
 
32
32
  `npm pack --dry-run` 里必须能同时看到 **`lib/index.js`、`lib/client.js`、`lib/bridge.mjs`、
33
- `dsh-eda-bridge-extension.zip`、`cordis.patch.yml`、`docs/`**。`lib/` 与 zip 是构建产物(被 gitignore),
33
+ `dsh-eda-bridge-extension-<线协议版本>.zip`、`cordis.patch.yml`、`docs/`**。`lib/` 与 zip 是构建产物(被 gitignore),
34
34
  由 `prepare` 脚本在打包时生成 —— 所以**打包机必须是 Windows**(zip 用 PowerShell `Compress-Archive`)。
35
35
 
36
36
  ## 2. 首次手动发布(必须手动,顺序不能颠倒)
@@ -0,0 +1,152 @@
1
+ <!-- 本文件由 scripts/gen-skill-doc.mjs 从 src/skills-content.ts 生成,请勿手工编辑。 -->
2
+ <!-- 同一份内容同时作为 DSH 技能 jlceda-schematic-workflow 的正文,以及系统提示精简版的来源。 -->
3
+
4
+ # 嘉立创EDA 项目全流程手册(dsh-eda-mcp)
5
+
6
+ 覆盖「打开/新建工程 → 原理图 → 同步到 PCB → 布局布线 → 校验 → 出 Gerber」全链路,
7
+ 以及每一步已经踩过的坑与处置办法。工具前缀统一是 mcp__jlceda__。
8
+
9
+ ## 0. 适用范围与硬前提
10
+
11
+ - 原理图坐标单位 0.01 英寸,原点在 A4 图框左下角,y 向上;图框 x 0~1170 / y 0~825。
12
+ - 标题栏占 x 460~1160 / y 10~190,必须避让;先 eda_get_page_info 读图框与安全区。PCB 坐标单位 mil。
13
+ - 绝大多数原理图 API 只作用于「当前活动文档」:返回空先 eda_get_active_document,再 eda_open_document 切页。
14
+ - 线协议版本必须桥接与扩展一致:eda_status 的 extensionVersions 是每个页面连上来的版本;
15
+ 不一致说明装的是旧扩展,需重新导入 dsh-eda-bridge-extension-<版本>.zip 并重启应用(不是 reload)。
16
+ - 默认禁止 eda_auto_layout / eda_auto_route(需 force:true 且设置里放行)。
17
+ 版面检查用「导出图片自行识别」,不要让 EDA 自动重排。
18
+
19
+ ## 1. 项目层:列出 / 打开 / 新建 / 保存 / 导出
20
+
21
+ - 列工程:eda_list_projects。无过滤时遍历所有本地目录聚合,字段 friendlyName / teamUuid / uuid。
22
+ 半离线模式下每个本地工程目录就是一个 team,其 uuid 就是目录路径。
23
+ - 打开工程:eda_open_project({ name }) 支持中文工程名(精确优先,其次忽略大小写包含)。
24
+ 返回的 opened 是「已观察到的活动工程」,另有 openReturned 反映 API 原始布尔。
25
+ - 新建工程:createProject 在本机构建上无副作用,**用 eda_import_project 导入工程文件代替**:
26
+ eda_import_project({ path, teamUuid, friendlyName, open:true }),teamUuid 取 eda_list_teams 的目录路径。
27
+ - 导出:eda_export_project({ outPath }) 落盘并返回字节数;不给 outPath 只回元数据,inline:true 才回 base64。
28
+ - 保存:eda_save_document(原理图)/ eda_pcb_save_document(PCB)。关应用前先保存。
29
+ - 不可用(实测):createProject / deleteProject / copyProject 对本地工程无效;
30
+ 删除与复制请在应用内完成,复制也可「导出 + 导入」得到独立副本。
31
+
32
+ ## 2. 原理图:先读清楚再动手
33
+
34
+ - eda_get_active_document → 确认 documentTypeName 是原理图页(HOME / PCB 都不行)。
35
+ - eda_get_page_info → 图框、标题栏、安全区(main / lowerLeft)。
36
+ - eda_get_components({ includeBounds:true }) → designator、value、x/y、包围盒,用来判断重叠。
37
+ - eda_get_pins({ componentPrimitiveId }) → 一次拿到 pinName / pinNumber / x / y / rotation / noConnected,
38
+ 不要逐脚调 raw sch_PrimitivePin.get。
39
+ - eda_get_wires / eda_get_nets → 现有连线与网络;eda_get_net_labels → 标签、网络端口、旗标与文本标签。
40
+ - eda_get_project → 工程结构(board → schematic / pcb 的 uuid),后面切页与 PCB 同步都要用。
41
+
42
+ ## 3. 原理图:布局规范
43
+
44
+ - 栅格 10 单位对齐;同块内器件等间距(建议 ≥30 单位),块间留 ≥40 单位。
45
+ - 信号流左→右;电源旗标朝上、地旗标朝下;主控居中,去耦电容贴电源脚(≤20 单位),晶振贴芯片且周围净空。
46
+ - 器件之间留 ≥20 单位用于走线与标签,避免标签压住符号或引脚号。
47
+ - 分区用 eda_draw_functional_box(虚线框 + 文本标注):电源 / 主控 / 接口 / 信号处理。
48
+ - 挪已有器件用 eda_move_component(保 designator/value),不要「删除 + 重放」。
49
+ - 摆完一屏回读 eda_get_components 检查包围盒相交,有重叠先调开再连线。
50
+ - 版面自查:导出画布图片交给模型识别,而不是让 EDA 自动重排(自动布局会把分好的区打散)。
51
+
52
+ ## 4. 原理图:连线与网络
53
+
54
+ - 局部连接用 eda_draw_wire(直线或 45°),不要穿过器件符号,不要与其它导线重叠。
55
+ - **跨区域同名网络必须用 eda_place_net_port 或网络标签**:eda_draw_wire 的 net 只对悬空导线有效,
56
+ 端点一接触引脚,EDA 按连通性重算网络名(实测 TESTNET 被并入 LED_A)。「两处画同名导线」不成立。
57
+ - 网络标签:eda_place_net_label 先真实调 sch_PrimitiveAttribute.createNetLabel;该 API 在 3.2.186 上不响应,
58
+ 插件按会话缓存探测结论后自动降级为纯文本标签(无电气语义),连通性由 stub 导线承担。
59
+ - 引脚上放标签/旗标优先用 *_at_pin 变体:沿引脚方向外推 stubLength(默认 20)再放,避免压住符号。
60
+ - 差分对写成 USB_DP / USB_DM 两个网络,不要写 USB_DP/DM;网络名只允许字母数字下划线点加减号。
61
+ - 不用的引脚打未连接标记:eda_set_no_connect({ primitiveIds })。
62
+ - 删除图元:eda_delete_primitive 的 kind 支持 component / wire / text / netport / netflag / netlabel;
63
+ 网络端口不出现在 eda_get_components 中,只能用 eda_get_net_labels 审计后再删。
64
+
65
+ ## 5. 原理图:批量操作与超时控制
66
+
67
+ - 批量放标签用 eda_place_net_labels([{ pinPrimitiveId, net } | { x, y, net }]):一次调用、逐条 ok/error、
68
+ 返回 done / failed / total。不要串行上百次(会打爆调用超时且没有进度可查)。
69
+ - 批量未连接标记用 eda_set_no_connect({ primitiveIds }),内部并发 8。
70
+ - 单次调用建议 ≤20 个变更,中间夹一次读取(eda_get_net_labels / eda_get_components)作为进度锚点;
71
+ 超时后凭锚点知道完成到哪,而不是全量重来。
72
+ - 探测类失败只付一次代价:net label 能力探测结果按会话缓存,probe:true 才重测。
73
+
74
+ ## 6. 原理图:校验与交付
75
+
76
+ - eda_export_netlist → 已解析对象(parsed:true, netlist)。逐网络检查端点数 ≥2、无悬空单脚网络。
77
+ - eda_run_drc → 逐条明细(type / message / primitiveId / x / y),按 primitiveId 回画布定位后修。
78
+ - eda_export_bom(csv 已自动从 UTF-16 解码)→ 位号连续、封装非空、无 DUMMY。
79
+ - 交付前把网络名清单与需求表比对(命名一致性比 DRC 更容易漏)。
80
+
81
+ ## 7. PCB:从同步到出 Gerber
82
+
83
+ - 同步:eda_open_document 切到 PCB 页 → pcb_import_changes(默认异步,会弹应用自己的确认对话框)→
84
+ eda_pcb_wait_for_components 判定「新器件出现了」;不要用长超时硬等对话框。
85
+ - 读现状:pcb_get_layers、pcb_get_nets({detail:true})、pcb_get_components({includePins:true})。
86
+ - 板框:pcb_draw_board_outline({ points }) 生成 layer 11 的闭合 polyline。
87
+ 不要用 pcb_draw_track 画板框(铜线,layer 11 被拒),也不要用 region(只支持铜层/MULTI)。
88
+ - 布局:pcb_place_component / pcb_move_component 手工摆放(安装孔 → 板边接口 → 主控 → 配套器件);
89
+ 去耦电容距引脚 ≤2mm,晶振靠芯片且下方净空。
90
+ - 走线:pcb_draw_track(不传线宽按网络角色给默认值,低于 6mil 直接拒绝);改线用 pcb_modify_track;
91
+ 整网加粗用 pcb_set_net_track_width。
92
+ - 过孔:pcb_draw_via(默认孔径按角色给标准值;焊环 <0.2mm 拒绝,孔径 <0.3mm 警告)。
93
+ - 铺铜:pcb_create_pour(points 为 mil 扁平数组,自动闭合);先确认设计规则里铺铜间距 ≥6mil(建议 10mil)。
94
+ - 自动布线:eda_pcb_auto_route 默认不用;确需使用才 wait:true 或后台 + eda_pcb_job_status 轮询。
95
+ - 校验:eda_pcb_run_drc(includeVerboseError:true 拿逐条)+ eda_design_audit(线宽/过孔/网络名/板框/铺铜/DRC 只读体检)。
96
+ - 交付:eda_pcb_export_gerber(返回 zip 的 base64 data URL,大板可能几 MB)。
97
+
98
+ ## 8. 设计规则速查(工具已强制)
99
+
100
+ - 网络名:字母/数字/下划线/点/加号/减号,≤255 字符;空格、斜杠、括号、中文会被拒绝。
101
+ - 线宽:普通信号 ≥6mil(0.15mm)、去耦分支 10mil、主干电源 16mil、>500mA 或 GND 20mil。
102
+ - 过孔:信号 0.2/0.4mm、电源/GND 0.3/0.6mm、大电流 0.4/0.8mm;焊环 ≥0.2mm 强制。
103
+ - 铺铜:顶/底层铺 GND,与其它网络间距 ≥6mil(建议 10mil),导出前移除孤岛。
104
+ - 丝印:字符高度/宽度有最小值限制(见 docs/design-rules.md),丝印不得压焊盘。
105
+
106
+ ## 9. 故障与处置(现象 → 原因 → 动作)
107
+
108
+ | 现象 | 原因 | 动作 |
109
+ |---|---|---|
110
+ | connectedClients=0 / 报未连接 | EDA 没开、扩展没导入或没点「连接」、端口被占 | 先 eda_status 看 hint;必要时 eda_launch 起应用并等扩展连上 |
111
+ | extensionVersions 与 bridgeVersion 不一致 | 装的是旧扩展 | 重新导入对应版本 zip(文件名带版本号)并重启应用 |
112
+ | API method not allowed | 该 API 不在扩展白名单 | 调 eda_list_api_methods 看清单;优先用包装好的工具 |
113
+ | 调用 60s 超时 | 页面切走留下僵尸 socket,或单次改太多 | 只读调用会自动换页面重试一次;把批量拆到 ≤20/批 |
114
+ | 读图返回空 / null | 活动文档不是原理图页 | eda_get_active_document → eda_open_document 切页 |
115
+ | createNetLabel 无响应 | 3.2.186 该 API 不 resolve | 自动降级文本标签 + stub 导线;批量用 eda_place_net_labels |
116
+ | eda_get_net_labels 曾返回 0 | 以前只查属性图元 | 现在同时列文本标签(kind:text),可直接删 |
117
+ | 导线 net 被改掉 | 连通性重算覆盖指定名 | 跨区域改用网络端口 / 网络标签 |
118
+ | 器件位置重叠 | 没按栅格、没留间距 | eda_move_component 重排;摆完回读包围盒 |
119
+ | 导入 .epro2 后 uuid 冲突 | 应用原样复制内部 id | 看返回 collisions;避免同时打开源工程与新工程 |
120
+ | createProject / copyProject / deleteProject 空或 false | 该构建对本地工程不支持 | 用 eda_import_project 建;删除/复制在应用内做 |
121
+ | eda_launch 带 project 没打开工程 | 命令行路径被应用忽略 | 用 eda_open_project({ name }) 打开 |
122
+ | 关应用后改动丢失 | eda_close 走了强制路径 | 关前先保存;看返回的 forced |
123
+ | run_code 读大 JSON 被截断 | 宿主 read 有单行上限 | 用 node:fs 读盘或分片读 |
124
+
125
+ ## 10. 端到端剧本
126
+
127
+ A. 在已有工程里改原理图:
128
+ eda_list_projects → eda_open_project({name}) → eda_get_project(取 schematic uuid)→ eda_open_document
129
+ → eda_get_page_info → eda_get_components / eda_get_pins → 摆位(eda_place_component / eda_move_component)
130
+ → 连线 eda_draw_wire + 跨区域 eda_place_net_labels → eda_export_netlist 查端点 → eda_run_drc 看明细
131
+ → eda_save_document。
132
+
133
+ B. 新建工程并出板:
134
+ 准备空白/模板工程文件 → eda_import_project({ path, teamUuid, friendlyName, open:true })
135
+ → 原理图流程(同 A)→ eda_get_project 取 pcb uuid → eda_open_document(pcb) → pcb_import_changes
136
+ → eda_pcb_wait_for_components 等确认 → 板框/布局/走线/过孔/铺铜 → eda_pcb_run_drc + eda_design_audit
137
+ → eda_pcb_save_document → eda_pcb_export_gerber → eda_export_project 备份。
138
+
139
+ C. 只做 PCB:
140
+ eda_open_project → eda_get_project → eda_open_document(pcb) → pcb_get_nets(detail) / pcb_get_components(includePins)
141
+ → 板框与布局 → 走线(按角色线宽)→ 铺铜 → eda_pcb_run_drc + eda_design_audit → Gerber。
142
+
143
+ ## 11. 交付前检查清单
144
+
145
+ - [ ] eda_status:connectedClients ≥1 且版本一致。
146
+ - [ ] 网表:每个网络 ≥2 端点、无悬空;差分对成对;电源/地命名统一。
147
+ - [ ] DRC:原理图与 PCB 都跑过,明细逐条清零或已确认豁免。
148
+ - [ ] 设计规则:线宽/过孔/铺铜间距/丝印符合第 8 节。
149
+ - [ ] BOM:位号连续、封装非空、无 DUMMY。
150
+ - [ ] 视觉:导出图片自查,标签不压符号、器件不重叠、功能框清晰。
151
+ - [ ] 保存:文档已保存,工程已 eda_export_project 备份。
152
+ - [ ] Gerber 已导出且层数与板层一致。
package/docs/tools.md CHANGED
@@ -45,13 +45,15 @@ Design limits enforced by these tools (track widths, via sizes, net naming) are
45
45
  | `eda_get_page_info` | Return the current schematic page, the A4 frame range, the title-block keep-out range, and the recommended safe placement areas. All coordinates are MCP units (0.01 inch). | `paper?: string` |
46
46
  | `eda_get_schematic_pages` | List the schematic pages of the current schematic, or fetch one page by uuid. | `pageUuid?: string` |
47
47
  | `eda_search_components` | Search JLCEDA library devices by keyword. Returns candidate components with uuid/libraryUuid needed by eda_place_component. | `keyword: string, limit?: integer` |
48
- | `eda_get_pins` | List pins of one schematic component. Use the returned primitiveId with eda_place_net_flag_at_pin, eda_place_net_label_at_pin, or eda_set_no_connect. | `componentPrimitiveId: string` |
48
+ | `eda_get_pins` | List pins of one schematic component in a single round trip, including pinName and pinNumber (no per-pin sch_PrimitivePin.get needed). Use the returned primitiveId with eda_place_net_flag_at_pin, eda_place_net_label_at_pin, or eda_set_no_connect. | `componentPrimitiveId: string` |
49
49
  | `eda_get_components` | List components on the active schematic page (or all pages). Returns designator, value, x, y, rotation and bounding box when available. | `allSchematicPages?: boolean, includeBounds?: boolean` |
50
50
  | `eda_get_wires` | List wires on the active schematic page. | `` |
51
51
  | `eda_get_nets` | List nets of the current schematic project. Uses sch_Net.* first; when the schematic is not the active document those APIs return [] and this tool falls back to parsing sch_Netlist.getNetlist, reporting which source was used. | `name?: string, parseNetlist?: boolean` |
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
- | `eda_get_net_labels` | List net-label / attribute primitives on the active schematic page (sch_PrimitiveAttribute.getAll), optionally for one parent primitive. | `parentPrimitiveId?: string` |
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_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` | List every API method the connected extension accepts (its allow-list). Call it when eda_api_call answers "API method not allowed". | `` |
55
57
 
56
58
  ## Schematic: place & draw
57
59
 
@@ -63,13 +65,15 @@ Design limits enforced by these tools (track widths, via sizes, net naming) are
63
65
  | `eda_place_net_flag_at_pin` | Place a power/ground net flag at a pin WITHOUT covering the symbol: the pin direction is read from the pin rotation, a stub wire of stubLength MCP units (default 20) is drawn outwards from the pin with the net name, and the flag is placed at its end. Pass offsetX/offsetY to place it manually (that disables the stub) or stubLength=0 for the old on-pin behaviour. | `pinPrimitiveId: string, identification: string, net: string, stubLength?: number, offsetX?: number, offsetY?: number, rotation?: integer, mirror?: boolean, color?: string, lineWidth?: integer, lineType?: integer, paper?: string, allowOutsideFrame?: boolean` |
64
66
  | `eda_place_net_label_at_pin` | Place a REAL net label at a pin (sch_PrimitiveAttribute.createNetLabel; falls back to text and reports method) WITHOUT covering the symbol: a stub wire of stubLength MCP units (default 20) is drawn outwards along the pin direction and the label goes at its end. offsetX/offsetY place it manually (disables the stub); stubLength=0 keeps the old on-pin behaviour. | `pinPrimitiveId: string, net: string, stubLength?: number, offsetX?: number, offsetY?: number, rotation?: integer, fontSize?: number, color?: string, lineWidth?: integer, lineType?: integer, paper?: string, allowOutsideFrame?: boolean` |
65
67
  | `eda_set_no_connect` | Set or clear the no-connect flag on one or more schematic pins via sch_PrimitivePin.modify. | `primitiveIds: array, noConnected?: boolean` |
66
- | `eda_draw_wire` | Draw a schematic wire (polyline). Coordinates are MCP units (0.01 inch). | `points: array, net?: string, color?: string, lineWidth?: integer, lineType?: integer` |
68
+ | `eda_draw_wire` | Draw a schematic wire (polyline). Coordinates are MCP units (0.01 inch). IMPORTANT: the net argument only sticks on a floating wire — as soon as an endpoint touches a pin, EDA recomputes the net from connectivity and the name you passed is overwritten (measured: TESTNET merged into LED_A). To join same-named nets across regions use eda_place_net_port or a net label; do not rely on two distantly drawn wires sharing a name. | `points: array, net?: string, color?: string, lineWidth?: integer, lineType?: integer` |
67
69
  | `eda_draw_rectangle` | Draw a rectangle. topLeftY is the UPPER y coordinate (max y); height extends downward. Coordinates are MCP units. | `topLeftX: number, topLeftY: number, width: number, height: number, cornerRadius?: number, rotation?: integer, color?: string, fillColor?: string, lineWidth?: integer, lineType?: integer, fillStyle?: string` |
68
70
  | `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` |
69
71
  | `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` |
70
72
  | `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` |
71
- | `eda_place_net_label` | Place a real net label at x/y via sch_PrimitiveAttribute.createNetLabel (falls back to a plain text label when that API is missing, and reports which method was used). Coordinates are MCP units. | `x: number, y: number, net: string, fontSize?: number, rotation?: integer` |
72
- | `eda_delete_primitive` | Delete a schematic primitive by kind and primitive id. | `kind: string, primitiveId: string` |
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` |
75
+ | `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` |
76
+ | `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` |
73
77
 
74
78
  ## Schematic: automation & export
75
79
 
@@ -78,11 +82,11 @@ Design limits enforced by these tools (track widths, via sizes, net naming) are
78
82
  | `eda_save_document` | Save the active schematic document. | `` |
79
83
  | `eda_zoom_to_fit` | Zoom to fit all primitives in the active document. | `tabId?: string` |
80
84
  | `eda_zoom_to_region` | Zoom to a region. Schematic coordinates are MCP units. | `left: number, right: number, top: number, bottom: number, tabId?: string` |
81
- | `eda_run_drc` | Run schematic DRC and return the verbose result array. | `strict?: boolean` |
82
- | `eda_auto_layout` | Run schematic auto-layout (sch_Document.autoLayout). | `uuids?: array` |
83
- | `eda_auto_route` | Run schematic auto-routing (sch_Document.autoRouting). | `uuids?: array` |
85
+ | `eda_run_drc` | Run schematic DRC with includeVerboseError and return one entry per problem (type, message, primitiveId, x/y plus the raw record) instead of bare counts. | `strict?: boolean` |
86
+ | `eda_auto_layout` | Run schematic auto-layout (sch_Document.autoLayout). DISABLED by default: automated layout is not used unless the user asks for it. Pass force:true only then. | `uuids?: array, force?: boolean` |
87
+ | `eda_auto_route` | Run schematic auto-routing (sch_Document.autoRouting). DISABLED by default: route by hand unless the user explicitly asks. Pass force:true only then. | `uuids?: array, force?: boolean` |
84
88
  | `eda_export_netlist` | Export the schematic netlist as text (default JLCEDA format). Returns null when no schematic is active - check eda_get_active_document / open the schematic page first. | `type?: string` |
85
- | `eda_export_bom` | Export the schematic BOM. csv returns text; xlsx returns a base64 data URL. | `format?: string` |
89
+ | `eda_export_bom` | Export the schematic BOM. csv is decoded from UTF-16 to readable text; xlsx returns a base64 data URL. | `format?: string` |
86
90
  | `eda_create_board` | Create a board linking a schematic and a PCB (dmt_Board.createBoard). | `schematicUuid?: string, pcbUuid?: string` |
87
91
 
88
92
  ## Design rules
Binary file
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Connects to the local dsh-eda-mcp bridge process over WebSocket and executes
6
6
  * a strict allow-list of official EasyEDA Pro extension APIs. Import through:
7
- * Extensions → Import → select dsh-eda-bridge-extension.zip
7
+ * Extensions → Import → select dsh-eda-bridge-extension-<version>.zip
8
8
  * then enable "Allow interactive with external" for this extension.
9
9
  */
10
10
  var DSH_EDA_MCP = {