插件开发指南

开发自有插件接入 LabCode:七类通用通道、工具链检测、类型化能力、命令 / 视图 / 项目类型声明、manifest 契约与示例。

LabCode 的插件系统面向第三方开放:任何开发者都可以编写插件,把自定义工具链接入 AI 智能体与 UI,无需修改 LabCode 本体。插件通过 manifest.json 声明工具、类型化能力、命令、视图与项目类型,宿主统一分发渲染——UI 与 AI 同源获得插件能力。

插件结构

一个插件就是一个目录(安装后位于 %APPDATA%\LabCode\plugins\{id})。目录按需存在,只有 manifest.json 是必填的:

my-toolchain/
├── manifest.json          # manifest(必填)
├── ui/                    # Web 视图页面(views.webview 的 entry,可选)
├── tools/                 # cli 插件的可执行脚本 / 二进制(可选)
├── proto/                 # gRPC 插件自带的 .proto(可选,复用宿主服务则不需要)
└── assets/                # 插件自带资源(如 lib/ 库文件;可选)
说明:运行时宿主还会创建 bin/(dependencies 下载的二进制),不属于插件打包内容。

manifest.json 最小结构

{
  "id": "my-toolchain",          // kebab-case,全局唯一
  "name": "我的工具链",
  "version": "1.0.0",
  "developer": "你的名字",
  "icon": "🔧",
  "capabilities": {
    "compile": { "transport": "internal", "service": "arduinoCli", "method": "compile", "output": "avr-gcc" },
    "board-manage": { "transport": "internal", "service": "arduinoCli", "method": "board.search" }
  }
}

安装时宿主 validateManifest 校验结构:能力 keys、工具 transport、命令 kind/placement、项目类型 scaffold 路径安全(拒绝绝对路径 / .. 穿越)、视图 entry 等,非法 manifest 拒绝安装。

插件图标

manifest.json 的 icon 字段声明插件图标,出现在活动栏、插件管理列表、市场卡片、新建项目页。支持三种形式:

形式说明示例
emoji直接写 emoji 字符"icon": "🔧"
lucide 图标名宿主渲染层映射 lucide 线条图标(小写 kebab)"icon": "box"
品牌标识品牌 LOGO:在宿主渲染层注册 React 组件,icon 写标识字符串"icon": "wokwi"

七类通用通道

每个工具通过 transport 声明走哪类通道。所有通道都是宿主通用驱动,插件只需声明,无需宿主预注册。

transport含义
cli一次性命令行(spawn 数组参数防注入)
httpREST API(全局 fetch,尊重代理)
grpc插件自带 .proto,宿主动态加载连接插件 daemon
mcp调用插件声明的 MCP 服务器工具
mqtt通用 MQTT 设备通道(连接 broker / 订阅 / 发布 / 请求-响应)
internal宿主标准能力(串口 / 日志 / 状态 / Arduino / toolchain)
backend调用插件自声明的 stdio 后端(JSON-RPC over stdin/stdout)

1. cli — 命令行工具(最常用)

一次性命令行工具。宿主用 spawn(数组参数,不经 shell,防注入)执行:

{
  "name": "flash",
  "description": "烧录固件到设备",
  "parameters": {
    "type": "object",
    "properties": {
      "hexPath": { "type": "string", "description": "固件文件路径" }
    },
    "required": ["hexPath"]
  },
  "transport": "cli",
  "category": "execute",
  "cli": {
    "command": ["esptool.py", "--port", "{port}", "write_flash", "0x0", "{hexPath}"],
    "parse": { "type": "json", "pick": "result" },
    "successCodes": [0],
    "timeoutMs": 30000
  }
}

2. http — REST API

{
  "name": "query_sensor",
  "description": "查询传感器数据",
  "transport": "http",
  "category": "query",
  "http": {
    "url": "https://api.example.com/sensors/{id}/data",
    "method": "GET",
    "query": { "key": "{apiKey}" },
    "headers": { "Authorization": "Bearer {token}" },
    "parse": { "type": "json", "pick": "data.value" },
    "timeoutMs": 10000
  }
}

3. grpc — 动态 proto(自带 .proto)

{
  "name": "compile",
  "description": "编译工程",
  "transport": "grpc",
  "category": "execute",
  "grpc": {
    "service": "mypkg.ToolService",
    "method": "Compile",
    "proto": "proto/tool.proto",
    "backendId": "default"
  },
  "backends": [
    {
      "type": "grpc",
      "command": "mytool-daemon",
      "port": 0,
      "args": ["daemon", "--port", "0"],
      "readiness": { "kind": "grpc", "timeoutMs": 20000 }
    }
  ]
}

service 用 proto 内全限定名,proto 为插件目录内 .proto 相对路径;宿主只连接该插件自己声明的 backend 端口(安全边界)。

4. mcp — 调用 MCP 服务器工具

{
  "mcpServers": [
    { "name": "browser", "command": "npx", "args": ["-y", "@playwright/mcp"], "autoApprove": false }
  ],
  "tools": [
    {
      "name": "browser_navigate",
      "description": "打开网页",
      "transport": "mcp",
      "category": "query",
      "mcp": { "server": "browser", "tool": "navigate" }
    }
  ]
}

5. internal — 宿主标准能力

{
  "name": "list_ports",
  "description": "列出串口",
  "transport": "internal",
  "category": "query",
  "internal": { "service": "serialport", "method": "list" }
}

可用 internal 服务:serialport(串口列表/选择)、serialLog(后台串口日志)、state(板卡选项)、arduinoCli(Arduino 编译/烧录/库/板卡)、toolchain(工具链检测状态)。

6. backend — 调用插件自声明的 stdio 后端

{
  "name": "config_get",
  "description": "读取 Kconfig 符号当前值",
  "transport": "backend",
  "category": "query",
  "backend": { "backendId": "confserver", "method": "get_values", "timeoutMs": 20000 }
}

backend transport 调用插件 backends 里声明的 stdio 长驻后端(JSON-RPC over stdin/stdout),适合「有状态」的工具。

7. mqtt — 通用 MQTT 设备通道

{
  "mqttServers": [
    {
      "name": "printer",
      "url": "mqtts://{settings.printer.ip}:8883",
      "username": "bblp",
      "password": "{settings.printer.accessCode}",
      "tls": { "rejectUnauthorized": false },
      "topics": ["device/{settings.printer.serial}/report"],
      "allowedPublishTopics": ["device/{settings.printer.serial}/request"]
    }
  ],
  "tools": [
    {
      "name": "query_state",
      "description": "读取设备最新状态",
      "transport": "mqtt",
      "category": "query",
      "mqtt": { "server": "printer", "op": "read_state", "topic": "device/{settings.printer.serial}/report", "format": "json" }
    }
  ]
}

op 五种:publish(发命令)、request(发命令+等响应)、collect(读消息/等事件)、read_state(最新快照)、status(连接状态)。

安全:非回环 broker 强制 TLS;LAN/回环明文放行(状态带警告);allowedPublishTopics 发布白名单 fail-closed;密码用 {settings.*} 占位符存插件设置,永不进日志。

能力声明(UI 主按钮)

UI 主按钮(编译 / 上传 / 板卡 / 库管理 / 平台安装)按主动工具链路由到启用插件的类型化能力绑定。能力 id 枚举:

能力含义
compile编译(绑定可声明 output,宿主据此显示编译仪表)
upload烧录
flash刷写
debug调试
board-manage板卡管理
board-select选择开发板
library-manage库管理
platform-install平台安装
{
  "capabilities": {
    "compile": { "transport": "internal", "service": "arduinoCli", "method": "compile", "output": "avr-gcc" },
    "upload": { "transport": "internal", "service": "arduinoCli", "method": "upload" }
  }
}

每个能力绑定一个工具后端调用(transport + service + method),UI 编译/上传按钮与 AI 工具经同一条能力路由执行。

命令 / 视图 / 项目类型(UI 入口)

插件除工具外,还可声明三种 UI 入口:

命令(commands)

{
  "id": "open-about",
  "title": "工具链信息",
  "icon": "🧛",
  "kind": "open-view",
  "view": "about",
  "placement": "sidebar.board.header"
}

项目类型(projectTypes)

{
  "id": "my-firmware",
  "title": "我的固件项目",
  "icon": "🔧",
  "scaffold": [
    { "file": "main.cpp", "content": "// {name} 项目骨架" }
  ]
}

新建项目页展示插件贡献的项目类型卡片,选中后按 scaffold 模板生成骨架({name} 占位符替换为项目名,宿主做路径安全清洗)。

视图(views,Web 视图)

{
  "id": "about",
  "title": "工具链信息",
  "icon": "🧛",
  "slot": "sidebar",
  "type": "webview",
  "entry": "ui/index.html"
}

设备面板(devicePanel)

活动栏「设备」标签是数据驱动的通用设备壳:插件声明设备面板(选择器 + 配置选项 + 动作 + 可选 webview),宿主渲染通用控件。

{
  "devicePanel": {
    "id": "arduino-board",
    "title": "Arduino 设备",
    "selectors": [
      {
        "id": "board", "title": "开发板",
        "source": { "transport": "internal", "service": "arduinoCli", "method": "board.search" },
        "searchable": true, "key": "fqbn", "placeholder": "搜索开发板…"
      },
      {
        "id": "port", "title": "端口",
        "source": { "transport": "internal", "service": "serialport", "method": "list" },
        "key": "port"
      }
    ],
    "actions": [
      {
        "id": "open-monitor", "title": "串口监视器", "kind": "action",
        "placement": "device-panel.action",
        "transport": "internal", "internal": { "service": "serialLog", "method": "open" }
      }
    ]
  }
}

工具链检测与一键安装

工具链插件可声明 detection(宿主通用检测引擎)与 installer(一键下载运行官方安装器)。检测结果存 pluginSettings.<pluginId>.toolchain,供 {settings.toolchain.active.*} 占位符使用:

{
  "detection": {
    "envVars": ["IDF_PATH"],
    "installerJson": {
      "paths": ["C:/Espressif/idf-env.json", "D:/Espressif/idf-env.json"],
      "selectedKey": "idfSelectedId",
      "entriesKey": "idfInstalled",
      "pathField": "path"
    },
    "pathGlobs": ["C:/Espressif/frameworks/esp-idf-v*"],
    "validateFile": "tools/idf.py"
  },
  "installer": {
    "url": "https://dl.espressif.com/dl/esp-idf/idf-installer.exe",
    "fileName": "idf-installer.exe"
  }
}

检测源按序:手动路径 → 环境变量(envVars)→ 官方安装器 JSON(installerJson)→ 路径 glob(pathGlobs)→ 校验文件(validateFile)。

依赖与后端

打包与发布

插件打包为 zip 上传到市场。zip 内可直接是 manifest.json 或包在一个子目录里。安装方式:插件市场一键安装,或「设置 → 插件 → 从文件夹安装」。

安全提示:插件拥有执行命令的能力,请只从可信来源安装。LabCode 对工具的参数注入有防护(cli 用数组参数、grpc 只连自身 backend),但插件作者声明的内容本身是受信任的。