• 简体中文
  • 插件运行与安全

    执行位置

    插件的业务代码、操作凭据、provider 进程和插件访问的本地文件都在选定 Desktop / Runner 上;声明的 UI 模块可在当前 Web / Desktop / 原生移动客户端运行。Web、移动端和服务端发起请求,Runner 执行请求。首次开发插件先读 Quickstart。

    组件职责
    Web / 移动端展示安装、配置、权限和审批,运行平台 UI 模块;不接收操作凭据
    API管理目录、安装与权限,验证设备,签名和路由请求
    Worker准备聊天工具、调度设备调用、恢复未完成操作
    Electron Main打开隔离配置窗口,使用系统安全存储保存凭据
    Runner校验请求、验证运行包、管理本地进程和消息日志
    Provider按公共 stdio MCP 契约执行已获准的业务请求

    服务端不会启动 provider,不会在设备离线时选择另一台设备或代为执行。通用 MCP 的当前限制及客户端模块执行边界见能力类型。

    设备连接

    设备登记保存长期公钥身份;租约(lease)是会过期的在线证明。Desktop 重连使用原登记,定期续租。撤销设备会更新设备代次(generation),拒绝旧连接和旧请求。

    配置等交互操作使用短期 user-gesture ticket,证明请求来自近期用户操作。Runner 控制通道使用 WSS ticket;通道路径为 /liyanlabs/ws/v1/runner/device。

    Redis 设备桥把请求送到持有该设备控制通道的 API 实例。请求有期限,不等待离线设备。设备离线、身份被撤销、运行包缺失或无法保存入站消息时,插件应显示不可用。

    发布渠道与信任

    Dev、Beta/Test、RC/UAT 和 Stable/Prod 各自使用独立的信任资源。Desktop 校验资源渠道、服务端 origin、精确 WSS 路径、公钥有效期和签名 key id。不能用其他渠道的 key 补齐缺失配置。

    错误应区分租约、信任资源、服务端签名、网络和协议问题。检查入口见设备连接失败。

    运行包

    可下载的第一方 runtime 与 Desktop 构建版本绑定,按需获取。它们不捆绑进安装器,也不在 API / Worker 容器执行。

    Runner 下载对应平台 archive,核对清单、文件大小与 SHA-256 摘要、每个文件的用途,再原子写入当前渠道的私有缓存。后续执行继续检查缓存证据。下载失败、平台不支持或校验失败时,能力不可用。

    作者需区分可移植能力清单与 Runner 原生 archive 清单,详见工具协议与运行产物。本地开发者包使用公共 /2 运行索引,由 Runner 从目录/archive 验证;服务端保存声明和声明的公开图标,不保存其代码或 Skill 字节。公开第三方下载发布仍未完成。

    客户端模块

    clientModules 分别声明 web / native 入口、文件及注入依赖。客户端按当前安装的版本图获取资源、校验摘要、加载 factory 并调用 apply(ctx, config);所有依赖须声明。它直接在客户端 JavaScript 环境执行,并非安全沙箱,用户需要信任作者。

    ctx.resources 按地址共享订阅,末位释放取消 I/O;ctx.connections.list 返回公开连接状态;ctx.tools.call 只调用当前安装获准的只读工具。业务和文件请求仍绑定确切在线 Runner,模块拿不到操作凭据或设备可执行路径。禁用、撤销、离线或版本变化撤回旧模块及服务权限。

    源码:service/pkg/core/plugin/clientmodule/、frontend/shared/src/core/pluginClientModules/ 和各平台模块运行入口。

    凭据配置

    配置请求 plugin_device_action 绑定 owner、安装、capability、release、配置 schema、目标设备代次和配置名称,不包含操作凭据。配置字段和可选注册入口由包资源声明。用户在绑定 Desktop 的原生窗口完成配置,Electron Main 用 safeStorage 加密保存到当前渠道私有目录。

    飞书优先扫码注册,已有应用可手动配置;GitHub 使用设备本地 token。服务端只保存配置名称、不透明身份、设备和凭据版本等元数据。飞书和 GitHub 连接的 credential_id 保持为空,操作凭据不进入 plugin_secret。

    空字段 schema 也须在原生窗口保存真实设备 profile。包内 setup Skill 引导 AI 读取状态、收集权限选择、请求原生确认并查询完成状态;请求已创建不代表窗口已打开或配置已保存。

    需要启动 provider 时,通过设备私有通道提供一次性凭据 bootstrap。不要把凭据放进聊天、清单、普通 Web / Mobile 表单、日志或公开 DTO。现有 OAuth 表和路由不代表已提供可用的服务端 provider 登录方案。

    每次调用的检查

    调用先确认当前安装、版本、连接和权限,再经设备桥发送给选定 Runner。服务端对请求签名;Runner 核对设备代次、状态修订、内容摘要、期限和请求身份,拒绝旧请求或被修改的请求。

    plugin-provider/1 是设备桥协议;工具进程使用 stdio MCP。Runner 通过私有继承句柄提供 plugin-provider-bootstrap/2,再完成 initialize 和整份工具目录匹配。会话按完整安装/capability/release/configuration/设备代次绑定,取消或撤销清理整个进程树。协议示例见开发与排障。摘要、修订和回执的含义见基本概念。

    实现检查位于 service/pkg/core/plugin/localprovider/、devicebridge/ 和 runner/crates/liyanlabs-runner/src/plugins/provider/。

    外部写操作

    发送消息、修改 issue 等操作要接入宿主审批。plugin_effect_intent 记录批准的动作、参数、目标,以及版本、权限和设备检查依据。条件变化后,旧批准不能用于另一个操作。

    结果含义作者如何处理
    failed_before_dispatch未跨过外部调用边界按宿主策略重试
    uncertain外部平台可能已经接受写入先查询或对账,不能直接重发
    reconciled_succeeded / reconciled_failed平台证据已确认结果使用确认结果结束处理

    插件权限字段 external_writes 只接受 prompt / deny。使用宿主的审批与结果回执,避免自己实现重复发送逻辑。

    入站消息与 Webhook

    飞书消息经本地长连接进入 Runner。Runner 先保存本地日志,再发给服务端;服务端验证、去重并持久化产品事件后确认接收。这条路径只在选定设备在线时工作。

    GitHub webhook 允许受控公网入口,流程是:

    1. 入口绑定账户、安装、连接、版本和设备代次。
    2. 服务器验证签名、事件类型、delivery id,并限制大小和速率。
    3. 立即转发到确切的在线 Runner。
    4. Runner 可靠保存消息并返回与正文摘要绑定的 ACK。
    5. 服务器收到 ACK 后才向 GitHub 返回成功。

    设备离线、请求超时或本地保存失败时返回可重试失败;不保存正文等设备上线后执行。服务器仅保存验证 webhook 来源所需的材料和去重回执,不保存 GitHub API token。

    改动这些路径时,核对 service/pkg/core/plugin/feishuchannel/、github/webhook_relay.go 和 Runner 入站处理源码。