mcpField
E
easyeda-api

easyeda-api

github.com/easyeda其他979631 次安装3 天前更新
代码仓库

关于 easyeda-api

easyeda-api 是面向使用 EasyEDA Pro 的 AI Agent 的技能,涵盖 API、文档格式和扩展开发。它将参考资料与 WebSocket 桥接服务结合,可在运行中的 EDA 客户端执行代码并验证行为。

主要功能

  1. 01API 类与类型参考
  2. 02通过 WebSocket 桥接执行代码
  3. 03PCB、原理图、库和项目操作范例
  4. 04项目、原理图与 PCB 源格式指南
  5. 05扩展开发与调试指导

适用场景

  1. 01开发 EasyEDA 扩展时查询 API
  2. 02在已连接的 EasyEDA Pro 中运行代码
  3. 03检查或修改 EasyEDA 文档源数据
  4. 04验证 PCB 和原理图操作

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/easyeda/easyeda-api-skill --skill easyeda-api

安装后在 Claude Code 中输入/easyeda-api确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
README.zh-Hans.md
format/
index.md
format/pcb/
obj.md
common.md
attr.md
3d.md
dimension.md
component.md
index.md
pad_via.md
panel.md
rule.md
partition.md
primitive.md
text.md
shape.md
format/project/
common.md
group.md
blob.md
index.md
meta.md
variant.md
instance.md
format/schematic/
common.md
obj.md
component.md
index.md
pin.md
shape.md

详细介绍

EasyEDA Pro API 技能

通过 AI 以编程方式控制 EasyEDA Pro(嘉立创EDA专业版)。此技能提供:

  1. 完整的 API 参考 — 120 个类、62 个枚举、70 个接口、19 个类型别名
  2. WebSocket 桥接 — 在运行中的 EasyEDA Pro 客户端内执行代码
  3. 代码模式 — PCB、原理图、库和项目管理的常见操作
  4. 文档源格式参考 — 用户需要直接分析或修改 EasyEDA 文档源文件,而非使用 API 时,可查阅项目、原理图和 PCB 源文件的格式规范

此技能不仅支持在 EasyEDA 中进行实时调试,也支持 EasyEDA 扩展开发。 在 EasyEDA 扩展开发过程中,AI Agent 可以使用此技能提供的扩展相关文档、API 参考、类型信息、用法示例和基于桥接的调试功能,查询 API、编写代码,并在集成和调试期间验证行为。

架构

┌───────────┐   HTTP/WS     ┌─────────────────┐   WebSocket   ┌───────────┐
│ AI Agent  │ ◄───────────► │  Bridge Server  │ ◄───────────► │  EasyEDA  │
│           │  Port Range   │  (Node.js)      │  Port Range   │  (Client) │
└───────────┘  49620-49629  └─────────────────┘  49620-49629  └───────────┘

服务器启动时会从 49620-49629 中自动选择一个可用端口。 AI 和 EDA 客户端都会通过扫描端口范围并验证握手(service: "easyeda-bridge") 自动发现服务器。

快速开始

1. 命令触发词

当用户说 “嘉立创EDA,启动!”、“立创EDA,启动!” 或 “EDA,启动!” 时:

重要:会话初始化 — 立即回复以下准确文本,以设置正确的会话标题:

📋 EasyEDA Session

然后继续执行以下设置步骤。

2. 安装依赖(如有需要)
cd ${CLAUDE_SKILL_DIR} && npm install
3. 启动桥接服务器

⚠️ 重要:桥接服务器必须在后台运行。切勿在前台运行,否则 AI 将一直等待服务器退出而被阻塞。

# Check if bridge is already running
for port in $(seq 49620 49629); do
  resp=$(curl -s http://localhost:$port/health 2>/dev/null)
  if echo "$resp" | grep -q '"easyeda-bridge"'; then
    echo "Bridge already running on port $port"
    BRIDGE_PORT=$port
    break
  fi
done

# Start bridge if not running
if [ -z "$BRIDGE_PORT" ]; then
  node ${CLAUDE_SKILL_DIR}/scripts/bridge-server.mjs &
  sleep 2
  # Find the port bridge is running on
  for port in $(seq 49620 49629); do
    resp=$(curl -s http://localhost:$port/health 2>/dev/null)
    if echo "$resp" | grep -q '"easyeda-bridge"'; then
      BRIDGE_PORT=$port
      break
    fi
  done
fi

echo "Bridge running on port: ${BRIDGE_PORT:-unknown}"
4. 连接 EasyEDA

在 EasyEDA Pro 中安装 run-api-gateway.eext 扩展。下载链接:

加载扩展后,它会自动建立 WebSocket 连接。

5. 验证连接并选择 EDA 窗口
# Check bridge and EDA connection status
curl http://localhost:${BRIDGE_PORT:-49620}/health

# List all connected EDA windows
curl http://localhost:${BRIDGE_PORT:-49620}/eda-windows

/eda-windows 的响应如下:

{
  "windows": [
    { "windowId": "abc-123", "connected": true, "active": true },
    { "windowId": "def-456", "connected": true, "active": false }
  ],
  "activeWindowId": "abc-123",
  "count": 2
}

根据窗口数量处理:

  • 0 个窗口:告知用户“没有连接 EasyEDA 窗口。请确保已在 EasyEDA 中安装并加载 EasyEDA 扩展(run-api-gateway.eext)。下载地址:https://jlc-ext.com/item/oshwhub/run-api-gateway”
  • 1 个窗口:自动选为活动窗口。告知用户:“✅ 已连接!活动 EDA 窗口:abc-123。可以开始工作了。”
  • 2 个或更多窗口:显示可用窗口,并请用户选择:
    Multiple EDA windows detected:
    - abc-123 (active)
    - def-456
    
    Which EDA window should I use?
    

选择窗口:

curl -X POST http://localhost:${BRIDGE_PORT}/eda-windows/select \
  -H "Content-Type: application/json" \
  -d '{"windowId": "abc-123"}'

选择后,确认:“✅ 活动 EDA 窗口:abc-123。可以开始工作了。”

6. 在 EDA 中执行代码
curl -X POST http://localhost:${BRIDGE_PORT:-49620}/execute \
  -H "Content-Type: application/json" \
  -d '{"code": "return await eda.dmt_Project.getCurrentProjectInfo();"}'

API 文档

完整的 API 参考位于 references/ 目录中:

  • references/_index.md — 所有类、枚举、接口和类型的总索引
  • references/_quick-reference.md — 所有方法签名,便于快速查找
  • references/classes/ — 120 个类文档(DMT_、PCB_、SCH_、LIB_、SYS_、IPCB_、ISCH_*)
  • references/enums/ — 62 个枚举文档
  • references/interfaces/ — 70 个接口文档
  • references/types/ — 19 个类型别名文档
如何查找 API
  1. 从 _index.md 开始,查找适用于任务的类或模块
  2. 阅读类文档(例如 references/classes/DMT_Board.md),查看所有方法和签名
  3. 使用 _quick-reference.md,快速查找所有类的方法签名
  4. 查看枚举和接口,了解参数类型和返回类型
文档源格式文档

如果用户需要直接分析或修改 EasyEDA 文档源,而不是使用 API,请使用 format/ 目录中的文档。

  • format/index.md — EasyEDA 文档源格式参考概览及版本说明
  • format/project/ — 项目源结构、元数据、二进制数据、变体和分组数据
  • format/schematic/ — 原理图源格式,包括结构、导线、形状、引脚、组件和表格
  • format/pcb/ — PCB 源格式,包括图元、焊盘和过孔、形状、文本、属性、规则和拼板数据

当任务涉及了解源布局、生成兼容的文档源,或编辑之后将重新导入 EasyEDA 的源数据时,请使用这些文件。

API 模块概览
前缀领域主要类
DMT_文档管理Board, EditorControl, Folder, Panel, Pcb, Project, Schematic, SelectControl, Team, Workspace
PCB_PCB 和封装Document, Drc, Event, Layer, Net, Primitive, PrimitiveComponent, PrimitiveLine, PrimitivePad, PrimitivePour, PrimitiveVia, SelectControl
SCH_原理图Document, Event, Primitive, PrimitiveComponent, PrimitiveWire, SelectControl
LIB_库3DModel, Cbb, Classification, Device, Footprint, LibrariesList, PanelLibrary, SelectControl, Symbol
SYS_系统Dialog, Environment, FileManager, FileSystem, FontManager, HeaderMenu, I18n, IFrame, LoadingAndProgressBar, Log, Message, MessageBox, MessageBus, PanelControl, Setting, ShortcutKey, Storage, Timer, ToastMessage, WebSocket, Window
IPCB_PCB 接口(图元)PrimitiveArc, PrimitiveComponent, PrimitivePad, PrimitiveFill, PrimitivePour, PrimitiveRegion, PrimitiveVia, ...
ISCH_原理图接口(图元)PrimitiveArc, PrimitiveComponent, PrimitiveWire, PrimitiveText, PrimitiveRectangle, ...
EPCB_ / ESCH_枚举PrimitiveType, Layer, PadType, ...

代码执行上下文

所有代码均在 EasyEDA Pro 的浏览器运行时中执行,形式如下:

async function(eda) {
  // Your code here — `eda` is the global EDA API object
  // You MUST use `return` to send results back
  // Do not add comments to the generated code, as the code is typically executed as a single line
}

重要规则:

  • eda 对象提供对所有 API 模块的访问权限(例如 eda.dmt_Board、eda.pcb_Primitive)。
  • 始终参阅 API 文档以确保正确使用。
  • 不要在生成的代码中添加注释,因为代码通常作为单行执行。
  • 始终使用 return 获取结果——不会捕获 console.log 输出。
  • 所有返回 Promise 的 API 方法都必须使用 await。
  • 代码在浏览器上下文中运行——无法使用 Node.js API(如 fs、path 等)。
  • 使用 eda.sys_Message.showToastMessage(msg) 向用户显示通知。
  • 查阅 API 文档并遇到枚举时,不要猜测枚举值。必须使用枚举成员,例如,在创建 PCB 图元时,图层参数应使用 EPCB_LayerId.TOP,而不是 1。
扩展运行时限制

编写 EasyEDA 扩展时,主进程中禁止使用标准浏览器 API。请使用 EDA 提供的替代方案:

用途❌ 禁止使用✅ 替代方案
获取用户输入—eda.sys_Dialog.showInputDialog()
用户选择—eda.sys_Dialog.showSelectDialog()
显示消息alert()eda.sys_Dialog.showInformationMessage()
确认操作confirm()eda.sys_Dialog.showConfirmationMessage()
Toast 通知操作 DOMeda.sys_Message.showToastMessage()
存储数据localStorage(主进程)eda.sys_Storage.setExtensionUserConfig(key, value)
自定义 UI操作宿主 DOMeda.sys_IFrame.openIFrame()
显示 HTMLshowInformationMessage(html)必须使用 iframe
打开链接window.open()eda.sys_Window.open()
浏览器硬件 API在主进程中使用在 iframe 中可用(navigator.serial 等)

注意: localStorage、window、document 等在 sys_IFrame 内可用,但在主扩展进程中不可用。

扩展 ↔ IFrame 数据传递

主扩展进程和 sys_IFrame iframe 是隔离上下文。如需在两者之间传递数据:

选项 A(推荐): 使用 eda.sys_Storage 作为桥接

// In main extension process:
await eda.sys_Storage.setExtensionUserConfig('myKey', JSON.stringify(data));

// In iframe:
const data = JSON.parse(await eda.sys_Storage.getExtensionUserConfig('myKey'));

选项 B: 两种上下文都可以直接访问 eda——从任一侧调用相同的 API

// In iframe HTML (NOT window.parent.eda):
const info = await eda.dmt_Project.getCurrentProjectInfo();

通信协议

端口发现

桥接服务会监听 49620-49629 范围内第一个可用的端口。 要查找服务,请扫描该端口范围并验证服务标识:

for port in $(seq 49620 49629); do
  resp=$(curl -s http://127.0.0.1:$port/health 2>/dev/null)
  if echo "$resp" | grep -q '"easyeda-bridge"'; then
    BRIDGE_PORT=$port; break
  fi
done
握手
  • HTTP:GET /health 返回 { "service": "easyeda-bridge", "edaConnected": bool, ... }
  • WebSocket:连接时,服务端发送 { "type": "handshake", "service": "easyeda-bridge" }
  • 客户端在使用连接前,必须验证 service === "easyeda-bridge"
消息格式

通过 WebSocket / HTTP 传输的 JSON 消息:

字段类型说明
type"execute" | "result" | "error" | "ping" | "pong" | "handshake"消息类型
idstring用于匹配请求与响应的请求 UUID
codestring要执行的 JavaScript 代码(用于 execute 类型)
resultany执行结果(用于 result 类型)
errorstring错误消息(用于 error 类型)
servicestring服务标识符(用于 handshake 类型)
timestampnumberUnix 毫秒时间戳

常见模式

项目和电路板操作
// Get current project info
return await eda.dmt_Project.getCurrentProjectInfo();

// List all boards in project
return await eda.dmt_Board.getAllBoardsInfo();

// Create a new board (optionally link to schematic/PCB)
return await eda.dmt_Board.createBoard();

// Switch to a document tab
await eda.dmt_EditorControl.activateDocument(tabId);
示例:按名称打开项目并打开其第一个原理图页
const targetProjectName = 'NE555 Circuit';

// 1. Enumerate projects by team/folder and find the target by name
const teams = await eda.dmt_Team.getAllTeamsInfo();
const seenProjectUuid = new Set();
let targetProjectUuid = null;

for (const team of teams || []) {
  const teamProjects = await eda.dmt_Project.getAllProjectsUuid(team.uuid);
  for (const projectUuid of teamProjects || []) {
    if (seenProjectUuid.has(projectUuid)) continue;
    seenProjectUuid.add(projectUuid);

    const info = await eda.dmt_Project.getProjectInfo(projectUuid);
    const name = info?.friendlyName || info?.name || '';
    if (name === targetProjectName) {
      targetProjectUuid = projectUuid;
      break;
    }
  }
  if (targetProjectUuid) break;

  const folderUuids = await eda.dmt_Folder.getAllFoldersUuid(team.uuid);
  for (const folderUuid of folderUuids || []) {
    const folderProjects = await eda.dmt_Project.getAllProjectsUuid(team.uuid, folderUuid);
    for (const projectUuid of folderProjects || []) {
      if (seenProjectUuid.has(projectUuid)) continue;
      seenProjectUuid.add(projectUuid);

      const info = await eda.dmt_Project.getProjectInfo(projectUuid);
      const name = info?.friendlyName || info?.name || '';
      if (name === targetProjectName) {
        targetProjectUuid = projectUuid;
        break;
      }
    }
    if (targetProjectUuid) break;
  }
  if (targetProjectUuid) break;
}

if (!targetProjectUuid) {
  throw new Error(`Project not found: ${targetProjectName}`);
}

// 2. Open the project
const opened = await eda.dmt_Project.openProject(targetProjectUuid);
if (!opened) {
  throw new Error(`Failed to open project: ${targetProjectName}`);
}

// 3. Get the first schematic page and open it
const schematics = await eda.dmt_Schematic.getAllSchematicsInfo();
if (!Array.isArray(schematics) || schematics.length === 0) {
  throw new Error(`No schematics found in project: ${targetProjectName}`);
}

const firstSchematic = schematics[0];
const pages = await eda.dmt_Schematic.getAllSchematicPagesInfo();
const firstPage = (pages || []).find((page) => page.parentSchematicUuid === firstSchematic.uuid)
  || firstSchematic.page?.[0];

if (!firstPage) {
  throw new Error(`No schematic page found in: ${firstSchematic.name}`);
}

const tabId = await eda.dmt_EditorControl.openDocument(firstPage.uuid);

return {
  projectUuid: targetProjectUuid,
  schematicUuid: firstSchematic.uuid,
  pageUuid: firstPage.uuid,
  tabId,
};

注意:

  • 实际上,dmt_Project.getAllProjectsUuid() 并非一个全局且无需参数的枚举方法。要可靠地按名称查找项目,请先遍历团队,再遍历文件夹。
  • openProject(projectUuid) 可能会丢弃当前打开项目中未保存的更改。调用前请谨慎。
PCB 图元操作
// Get selected primitives
const selected = eda.pcb_SelectControl.getAllSelectedPrimitives_PrimitiveId();

// Create a line on copper layer
// Layer parameter uses EPCB_LayerId enum — see references/enums/EPCB_LayerId.md
await eda.pcb_PrimitiveLine.create(
  "GND",                       // net (string)
  EPCB_LayerId.TOP,            // layer — use enum, NOT raw number
  0,                           // startX (unit: 1mil)
  0,                           // startY (unit: 1mil)
  1000,                        // endX (unit: 1mil)
  0,                           // endY (unit: 1mil)
  10,                          // lineWidth
  false                        // primitiveLock
);

// Modify an existing primitive (async pattern)
const prim = await eda.pcb_PrimitiveComponent.get([id]);
const asyncPrim = prim.toAsync();
asyncPrim.setState_X(newX);
asyncPrim.setState_Y(newY);
asyncPrim.done();
PCB 异步图元模式(重要)

要修改 PCB/SCH 图元,必须使用异步模式:

// 1. Get the primitive
const prim = await eda.pcb_PrimitiveVia.get([viaId]);
// 2. Convert to async mode
const asyncPrim = prim.toAsync();
// 3. Set new values
asyncPrim.setState_X(newX);
asyncPrim.setState_Y(newY);
asyncPrim.setState_Diameter(diameter);
// 4. Apply changes
asyncPrim.done();
原理图操作
// Get all pages
return await eda.dmt_Schematic.getAllSchematicDocumentsInfo();

// Create a schematic component
// component parameter requires {libraryUuid, uuid} object — NOT a plain string
await eda.sch_PrimitiveComponent.create(
  { libraryUuid: "...", uuid: "device-uuid-from-library" },  // component object
  5000,                        // x (unit: 0.01inch = 10mil)
  5000,                        // y (unit: 0.01inch = 10mil)
  "",                          // subPartName
  0,                           // rotation (degrees, plain number)
  false,                       // mirror
  true,                        // addIntoBom
  true                         // addIntoPcb
);

// Get selected schematic primitives
const ids = eda.sch_SelectControl.getAllSelectedPrimitives_PrimitiveId();
库操作
// List all libraries in workspace
return await eda.lib_LibrariesList.getAllLibrariesList();

// Search devices
return await eda.lib_Device.search("STM32");

// Get symbol info
return await eda.lib_Symbol.get(symbolUuid);
系统函数
// Show toast message
eda.sys_Message.showToastMessage("Operation complete!");

// Show confirm dialog
const confirmed = await eda.sys_Dialog.showConfirmationMessage("Proceed?");

// File system (limited to extension sandbox)
const content = await eda.sys_FileSystem.readFileFromFileSystem(path);
await eda.sys_FileSystem.saveFileToFileSystem(path, content);
DRC(设计规则检查)
// Run DRC check
const passed = await eda.pcb_Drc.check(true, true, false);
// passed is boolean: true if DRC passed, false if errors found

常见错误

仔细阅读 API 签名(至关重要)

调用任何 API 方法之前,必须从 references/ 中阅读完整签名,包括参数类型、返回类型和备注。

AI Agent 经常会因匆忙浏览文档而犯下以下错误:

错误 1:没有对返回 Promise 的方法使用 await

几乎所有 EDA API 方法都会返回 Promise<T>。如果忘记使用 await,得到的将是 Promise 对象,而不是实际结果。

// WRONG: Missing await — result is a Promise, not the project info
const project = eda.dmt_Project.getCurrentProjectInfo();
console.log(project); // Promise { <pending> }

// CORRECT: Always await async methods
const project = await eda.dmt_Project.getCurrentProjectInfo();
console.log(project); // { uuid: "...", name: "...", ... }

**如何判断方法是否需要使用 await:**查看签名中的返回类型。如果显示 Promise<...>,就必须使用 await。

// From references/classes/DMT_Project.md:
getCurrentProjectInfo(): Promise<IDMT_ProjectItem | null>
//                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                       This is a Promise — you MUST await it

错误 2:使用原始数字,而不是枚举值

许多参数都需要特定的枚举值。使用错误的数字不会报错,却会导致行为不正确。

// WRONG: What does layer "1" mean? Which copper layer? Signal? Mask?
await eda.pcb_PrimitiveLine.create("GND", 1, 0, 0, 1000, 0, 10, false);

// CORRECT: Use the enum — EPCB_LayerId.TOP is clear and type-safe
// Check references/enums/EPCB_LayerId.md for the correct value
await eda.pcb_PrimitiveLine.create("GND", EPCB_LayerId.TOP, 0, 0, 1000, 0, 10, false);

使用数值常量之前,务必先在 references/enums/ 中查找对应的枚举。

错误 3:未经确认就假定参数类型

不同 API 使用的单位、ID 格式和可选参数约定各不相同。切勿想当然。

// WRONG: Assuming create() parameters match modify() parameters
// create() and modify() often have DIFFERENT parameter orders/types

// CORRECT: Always read the exact signature for the method you're calling
// Check references/classes/<ClassName>.md for each method's specific signature

总结 — 每次调用 API 之前:

  1. 阅读签名——查看参数类型、返回类型和 references/classes/ 中的所有内容
  2. 如果返回 Promise,就使用 await——检查返回类型是否为 Promise<...>
  3. 使用枚举——在 references/enums/ 中查找,不要猜测数字或字符串
  4. 检查备注——“备注”部分通常包含重要的使用说明
坐标单位(至关重要)

不同领域使用不同的坐标单位:

领域单位换算
PCB1mil1mm ≈ 39.37 个单位
原理图0.01inch(10mil)1mm ≈ 3.937 个单位

**这是 AI Agent 最常犯的错误。**混淆单位会导致元件放置位置不正确。

  • PCB:1 个单位 = 1mil = 0.001 英寸 = 0.0254 mm
  • 原理图:1 个单位 = 0.01inch = 10mil = 0.254 mm

如果使用了错误的单位,元件与预期位置的距离会相差 10 倍。

// WRONG: thinking unit is 1mil (it's actually 0.01inch = 10mil)
// Placing at x=500 thinking it's 500mil = 0.5inch — but 500 units = 5000mil = 5inch!
await eda.sch_PrimitiveComponent.create({libraryUuid: "...", uuid: "dev-uuid"}, 500, 0, "", 0, false, true, true);

// CORRECT: 50 units = 500mil = 0.5inch (in 0.01inch units)
await eda.sch_PrimitiveComponent.create({libraryUuid: "...", uuid: "dev-uuid"}, 50, 0, "", 0, false, true, true);
文档状态(至关重要)

创建项目后,必须先打开项目,然后才能对其中的文档进行操作。

操作文档时,务必确认:

  1. 项目已打开——使用 eda.dmt_Project.getCurrentProjectInfo() 进行确认
  2. 当前文档正确——使用 eda.dmt_SelectControl.getCurrentDocumentInfo() 检查文档类型
  3. 文档类型与 API 领域匹配——PCB API 需要当前文档为 PCB 文档,SCH API 需要当前文档为原理图文档
// WRONG: Assuming operation will work without checking document state
await eda.pcb_PrimitiveLine.create(...); // May fail if no PCB document is open

// CORRECT: Always verify document state first
const project = await eda.dmt_Project.getCurrentProjectInfo();
if (!project) {
  // If you just created a project, you MUST open it before any operations!
  return "Error: No project is currently opened. If you just created a project using dmt_Project.createProject(), you MUST call dmt_Project.openProject(projectPath) to open it first. You cannot operate on documents until a project is opened.";
}

const doc = await eda.dmt_SelectControl.getCurrentDocumentInfo();
if (doc?.documentType !== EDMT_EditorDocumentType.PCB) {
  return "Error: No PCB document is currently active. Please open a PCB document first.";
}

// Now safe to perform PCB operations
await eda.pcb_PrimitiveLine.create(...);

**对错误的文档类型进行操作会返回错误或 null 结果。**例如:

  • 当前没有 PCB 文档(documentType !== EDMT_EditorDocumentType.PCB)时执行 PCB_* API → 错误/null
  • 当前没有原理图文档(documentType !== EDMT_EditorDocumentType.SCHEMATIC_PAGE)时执行 SCH_* API → 错误/null
IFrame 上下文 — 始终直接使用 eda(至关重要)

编写通过 sys_IFrame.openIFrame() 创建 iframe 的扩展代码时,iframe HTML 中的 JavaScript 代码可以直接访问全局对象 eda。不要使用 window.parent.eda。

原因: EasyEDA 会自动将 eda 对象注入 iframe 的执行上下文。标准的浏览器跨框架访问方式(window.parent、parentWindow 等)在此处并不适用,会导致失败。

// WRONG: Using window.parent to reach parent frame's eda object
// This is a common mistake made by AI agents familiar with web iframe patterns
const project = await window.parent.eda.dmt_Project.getCurrentProjectInfo();

// CORRECT: eda is available directly in the iframe context
const project = await eda.dmt_Project.getCurrentProjectInfo();

此规则适用于 sys_IFrame iframe 中的所有代码:

  • 通过 openIFrame() 加载的扩展 UI 面板
  • 扩展包中在 iframe 内显示的任何 HTML 文件

**规则:**在 EasyEDA 扩展中,无论代码运行在主上下文中,还是运行在由 sys_IFrame 创建的 iframe 中,都始终通过 eda.xxx 访问 API——绝不要使用 window.parent.eda 或任何其他父框架访问方式。

多窗口支持

当多个 EasyEDA 窗口连接到桥接服务时,无需在每次 EDA 操作时检查窗口选择。仅在以下情况检查:

  1. 首次 EDA 操作 — 确认哪个窗口处于活动状态,并告知用户
  2. EDA 断开连接错误 — 如果桥接服务返回 EDA 已断开连接的错误,请让用户选择一个新窗口

多窗口操作:

# List all connected EDA windows
curl http://localhost:49620/eda-windows

# Select a specific window
curl -X POST http://localhost:49620/eda-windows/select \
  -H "Content-Type: application/json" \
  -d '{"windowId": "abc-123-def"}'

# Execute on specific window
curl -X POST http://localhost:49620/execute \
  -H "Content-Type: application/json" \
  -d '{"code": "return await eda.dmt_Project.getCurrentProjectInfo();", "windowId": "abc-123-def"}'

如果只连接了一个 EDA 窗口,则会自动将其选为活动窗口。

调试技巧与故障处理策略

故障排查
  1. 始终先检查运行状况:扫描 49620-49629 端口,查找 {"service":"easyeda-bridge"}
  2. EDA 未连接?:确保 EasyEDA 中已加载桥接扩展。下载地址:https://jlc-ext.com/item/oshwhub/run-api-gateway
  3. 超时错误:默认超时时间为 30s。如果发生超时:
    • 检查是否已打开正确的项目和文档(使用 dmt_Project.getCurrentProjectInfo())
    • 如果未打开项目,使用 dmt_Project.openProject(projectPath) 打开一个项目
    • 如果没有活动文档,使用 dmt_EditorControl.openDocument(docId) 打开正确的文档类型(PCB/原理图)
    • 如果文档类型不正确(例如,在原理图上运行 PCB API),请先切换到正确的文档
    • 复杂操作可能需要拆分代码
  4. 检查返回值:许多方法失败时会返回 null,务必进行验证
  5. 图层编号:使用 references/enums/ 文档中的枚举(例如,EPCB_LayerId)
  6. EDA 窗口已断开连接:如果收到窗口已断开连接的错误,使用 GET /eda-windows 检查可用窗口,并使用 POST /eda-windows/select 切换到另一个窗口
  7. 权限错误:所有 API 接口均由 EDA 的权限系统控制。如果某个特定 API 持续执行失败(返回错误或 null),而其他 API 工作正常,并且你已确认调用与文档完全一致,则问题可能是权限受限,而非代码错误。EDA 客户端可能会根据用户许可证、项目设置或文档状态限制某些操作。请告知用户,该操作可能需要更高权限或不同的 EDA 版本。
  8. 错误持续存在?:如果你已确认 API 调用与文档完全一致、排除了权限问题,但仍遇到意外错误,请考虑通过 EasyEDA 官方支持渠道报告问题
故障处理规则

开发扩展时,请遵循以下规则:

情况操作
文档中不存在该 API 方法立即停止 — 告知用户该 API 不存在
阅读文档后仍无法确定签名停止生成 — 返回查询步骤并重新阅读
检测到被禁止的浏览器 API自动替换为 eda.sys_* 替代方案
菜单 ID 冲突添加前缀以区分(例如,my-plugin-home、my-plugin-sch)
权限受限告知用户 — 可能需要不同的 EDA 版本或许可证

重要: 切勿猜测 API 签名。如果 references/classes/ 中没有相关文档,则该 API 不适用于你的用例。

AI Agent 工作流

当用户要求你执行 EDA 操作时:

  1. 了解任务 — 属于哪个领域?(PCB/SCH/LIB/Project)
  2. 验证文档状态 — 检查 eda.dmt_Project.getCurrentProjectInfo() 和 eda.dmt_SelectControl.getCurrentDocumentInfo()
  3. 确认正确的文档类型 — PCB 操作需要激活的 PCB,SCH 操作需要激活的原理图
  4. 查阅 API — 阅读 references/ 中相关类的文档
  5. 检查类型 — 阅读枚举/接口文档,了解参数类型
  6. 编写代码 — 遵循上述执行上下文规则
  7. 执行 — 通过 POST /execute 发送并检查结果
  8. 迭代 — 如果发生错误,阅读错误消息并进行调整

不确定某个 API 时:

  • 在 _quick-reference.md 中搜索方法名称
  • 阅读特定类的文档,了解详细签名和说明
  • 查看接口文档,了解复杂参数类型

会话管理

检测主题变更

Bridge 服务在运行时会占用系统资源。如果用户连续 3 次 转向完全不同的主题(与 EasyEDA/EDA/PCB/原理图无关),请主动询问是否要关闭 Bridge:

"我注意到我们已经转向 EasyEDA 以外的话题。Bridge 服务仍在后台运行。你想停止它以释放资源吗?"

不要自动关闭 Bridge — 用户之后可能会切回 EDA 工作。只需询问,并在用户确认后关闭。

关闭 Bridge

如果用户确认要停止 Bridge:

# Find and stop the bridge process
for port in $(seq 49620 49629); do
  pid=$(lsof -ti :$port 2>/dev/null)
  if [ -n "$pid" ]; then
    kill $pid
    echo "Bridge stopped (PID: $pid, Port: $port)"
    break
  fi
done

评论

支持 Markdown