• 简体中文
  • 插件开发与排障

    使用本手册启动本地插件栈、配置 device-local provider、追踪生命周期失败,并在不削弱 local-first 边界的前提下扩展目录能力。

    本地环境

    从同一个 checkout 启动常规服务栈与 Desktop/Runner:

    just dev
    just desktop-dev

    本地 origin 是 https://scilaxy.local。不要同时从两个 worktree 运行完整 Compose 栈;stack、数据库、Redis、端口和 Desktop 连接都是共享资源。

    just dev 会在服务启动前准备 Dev 插件 authority。desktop/scripts/provision-dev-plugin-runner.mjs 生成或复用以下忽略提交的本地材料:

    • Dev 服务端 Ed25519 signing key;
    • plugin-secret 加密 keyring;
    • Dev channel home 下的公开 trust resource。

    just desktop-dev 生成并暂存 runtime manifest、填充本地 runtime cache、构建 Runner、启动 Electron。API、Web、Worker 在 just dev 下热更新,普通源码修改不需要重建整套栈。

    排查插件前确认:

    1. Desktop 显示 channel dev、backend origin https://scilaxy.local
    2. Trust resource 指向精确 WSS origin 和 /scilaxy/ws/v1/runner/device 路径。
    3. Desktop enrollment 是 active,lease expiry 持续推进,并存在 catalog digest。
    4. Installation 与指定 device 属于同一个认证用户。

    配置本地 Profile

    飞书或 GitHub 必须先完成 connection,再启用:

    1. 安装插件并选择在线 Desktop。
    2. 输入 profile label。Trim 后必须有 1–128 个 Unicode code point,且只包含字母、数字、空格、._-
    3. 点击“前往桌面端配置”,创建 authorize_local_profile device action。
    4. 完成隔离 Electron 窗口。飞书需要 cnglobal、App ID、App Secret。
    5. 等待 connection 进入 ready,本地 provider probe 健康。
    6. 审核并保存插件请求权限。
    7. 启用 installation。

    Connection 与 permission 的先后可以交换,但二者必须存在。Profile label 为空时,前往 Desktop 的按钮会按设计禁用。

    插件包契约

    每个可移植 package 都包含根目录 plugin.json,遵循 Agent Plugins 1.0.0。Skill 从 skills/<name>/SKILL.md 发现;可选根目录 mcp.json 声明 MCP server。SciLaxy 专属本地执行能力声明在 extensions["ai.scilaxy"]

    最小 local-provider manifest 结构如下:

    {
      "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
      "name": "org.example.local-provider",
      "version": "1.0.0",
      "author": { "name": "Example Publisher" },
      "extensions": {
        "ai.scilaxy": {
          "schema": "https://scilaxy.ai/schemas/plugin-extension/1.0.0",
          "localProviders": [
            {
              "id": "example-local",
              "provider": "example",
              "toolCatalogDigest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
              "protocol": "plugin-provider/1",
              "transport": "stdio",
              "entrypoint": {
                "path": "bin/provider",
                "args": [],
                "workingDirectory": "."
              },
              "connectionModes": ["device_local"]
            }
          ]
        }
      }
    }

    示例 tool-catalog digest 必须替换为真实小写 SHA-256。Extension 是闭合 schema:localProviders 可以定义 package-relative stdio provider;inboundTransports 可以定义 provider WebSocket 或需 ACK 的 webhook relay;channels 当前只接受受支持的飞书/GitHub contract;agentRuntimes 仅允许 builtin source 和受支持 adapter。

    校验是确定、离线且不执行代码的,也不获取远程 schema。Package 只能包含普通文件和规范安全相对路径,禁止 link/device/socket 和带 credential 文件;最多 2,000 个文件、64 MiB 解压数据、32 层路径,压缩比不超过 100:1。非 bundled local provider 还必须在指定设备取得显式 host-authority consent。

    API 表面

    认证插件 REST 根路径为 /scilaxy/api/v1/plugins

    领域规范路由
    目录GET /catalogGET /catalog/:plugin_key/releases/:version
    安装GET/POST /installationsGET/DELETE /installations/:installation_id
    生命周期POST /installations/:id/{update,enable,disable,repair}GET /installations/:id/operations/:operation_id
    可观测性GET /installations/:id/healthGET /installations/:id/activity
    连接GET/POST /installations/:id/connections;detail GET/PATCH/DELETEauthorize/verify/revoke
    权限GET/PUT /installations/:id/permissions
    设备GET /devices;enrollment、activate、challenge、lease、ticket、revoke
    设备动作POST/GET /device-actions;claim、awaiting-confirmation、challenge、complete、fail、cancel
    外部效果GET /effects/:effect_id;decision 复用通用工具审批 API
    OAuth callbackGET /oauth/:provider/:region/:redirect_id/callback

    Runner 通道为 WSS /scilaxy/ws/v1/runner/device。GitHub 公网 ingress 为 POST /scilaxy/api/v1/plugin-webhooks/github/:endpoint_token

    规范 REST 路径没有尾斜杠。请求和响应的事实源位于 service/pkg/web/views/plugins/plugindevices/runnerws/

    Readiness 失败

    启用会提交异步生命周期命令。API 可以接受请求,而 Worker 随后仍会拒绝。必须同时读取最新 plugin_installation_operation 和 installation health blocker。

    Blocker含义恢复动作
    package_unavailable选定 release package 不可用或未验证恢复或重新发布精确 release
    connection_required声明的 provider 没有可用 connection创建本地 profile 或完成 OAuth
    reauthentication_requiredConnection 存在但 credential 已失效在绑定设备重新授权
    permission_required当前 permission document 未覆盖 capability审核并保存权限
    device_offline绑定设备没有有效租约启动该 Desktop/Runner 并续租,不静默换设备
    runtime_incompatibleAgent Runtime config、protocol 或 version 不兼容在目标设备 repair 或重新配置 runtime
    release_revokedRelease 已 quarantine 或 revoke更新到 available release
    policy_changedDeclaration、config digest 或 policy 无法继续证明重新安装/配置并批准当前声明

    Operation 级 requirements_unmet 只表示存在一个或多个 blocker,本身不等于 lease、signing 或 App Secret 失败。

    一个常见的新飞书安装失败会同时具备:

    • installation 是 disabled
    • 最新 Enable operation 以 requirements_unmet 失败;
    • 没有 readyplugin_connection
    • 没有当前 plugin_permission
    • device enrollment 与 lease 健康。

    此时重复登记设备、轮换服务端 key 或继续点击“启用”都不会恢复。应先完成本地 profile 和权限。

    设备连接失败

    设备 transport 与生命周期 readiness 必须分层排查:

    错误检查内容
    Leaselease_failed登录 owner、enrollment state、generation、challenge/renewal
    Trust resourcetrust_config_invalidBuild channel、WSS origin/path、公钥有效期/撤销
    Server signerserver_signing_unavailableTyped channel signing 配置和 active key id
    Transporttransport_unavailableWSS 可达性、Redis 是否绑定当前 API Pod
    Authorityauthority_rejectedOwner/device/ticket/generation 与冻结 revision/digest
    Protocolprotocol_rejectedDesktop/Runner/service 协议版本和严格 frame shape

    不要把它们全部归为“租约问题”,每层的恢复动作都不同。

    数据库诊断

    只使用只读查询,不打印 secret、ciphertext、nonce、原始 provider payload、ticket 或本地路径。

    列出当前 23 张表:

    SELECT tablename
    FROM pg_catalog.pg_tables
    WHERE schemaname = 'public'
      AND (tablename = 'plugin' OR tablename LIKE 'plugin\_%' ESCAPE '\')
    ORDER BY tablename;

    追踪 installation 和最新 operation:

    SELECT id, plugin_key, state, revision, release_id
    FROM plugin_installation
    WHERE user_id = '<user-id>'
    ORDER BY created_at DESC;
    
    SELECT id, kind, state, error_code, attempt, created_at, completed_at
    FROM plugin_installation_operation
    WHERE installation_id = '<installation-id>'
    ORDER BY created_at DESC;

    检查非秘密 connection 与 permission authority:

    SELECT id, provider_key,
           resource_scope_json->>'profile_label' AS profile_label,
           device_id, state, credential_id, credential_version, revision
    FROM plugin_connection
    WHERE installation_id = '<installation-id>';
    
    SELECT id, capability_id, revision, policy_digest, supersedes_id
    FROM plugin_permission
    WHERE installation_id = '<installation-id>'
    ORDER BY created_at DESC;

    检查 liveness 而不暴露 key material:

    SELECT id, state, lease_generation, lease_expires_at,
           app_channel, app_version, catalog_digest
    FROM plugin_device_enrollment
    WHERE user_id = '<user-id>'
    ORDER BY updated_at DESC;

    Enable 失败建议顺序:

    1. 最新 operation error code;
    2. health blockers;
    3. ready connection;
    4. 当前 permission coverage;
    5. 绑定 device lease/generation;
    6. 最后才查本地 runtime/package/provider health。

    新增插件

    1. 在唯一 catalog/manifest 事实源声明 plugin identity、immutable release、capability 和平台 runtime,不在可执行代码重复部署或展示事实。
    2. 复用闭合 capability schema。新增协议概念必须同步更新 validation、数据库 contract、API projection、Runner 和测试。
    3. 选择唯一 credential owner:device-local、server OAuth 或无 credential,不得混用。
    4. 使用 package-relative provider entrypoint 和闭合 argv、working directory、transport、verifier schema,禁止拼接 shell。
    5. 声明最小权限。外部写操作必须接入 effect intent、审批、receipt、reconcile。
    6. 入站事件使用本地长连接或受控 webhook relay,不增加云端执行 fallback。
    7. 测试 install、setup、permission、offline device、generation fence、revoked release、protocol drift、重试与歧义。
    8. 为 Web、Desktop、移动端提供等价状态和恢复信息。
    9. 同时更新中英文 Rspress 页面和 provider 专属文档。
    10. 使用真实 Desktop/Runner 完成从安装到 provider 调用的端到端验证。

    源码索引

    关注点源码
    内置目录与 authority digestservice/pkg/core/plugin/builtin/
    扩展 schemaservice/pkg/core/plugin/packagevalidator/schemas/plugin-extension.schema.json
    生命周期与 readinessservice/pkg/core/plugin/lifecycle/service/pkg/repo/plugin/lifecycle/
    当前账户 authorityservice/pkg/repo/plugin/currentauthority/
    Connection、permission、secretservice/pkg/repo/plugin/profile/service/pkg/repo/plugin/permission/service/pkg/repo/plugin/secret/
    Device 与 actionservice/pkg/core/plugin/device/service/pkg/repo/plugin/device/
    设备桥与 provider RPCservice/pkg/core/plugin/devicebridge/service/pkg/core/plugin/localprovider/
    外部 effectservice/pkg/core/plugin/effect/service/pkg/repo/plugin/effect/
    Runtime Session 与 eventservice/pkg/core/plugin/runtime/service/pkg/repo/plugin/runtime/
    HTTP/WSS viewservice/pkg/web/views/plugins/service/pkg/web/views/plugindevices/service/pkg/web/views/runnerws/
    Web 插件 UIfrontend/web/src/features/plugins/frontend/shared/src/service/pluginService.ts
    Runner 执行runner/crates/scilaxy-runner/src/plugins/
    Electron 凭据desktop/electron/src/plugins/
    Dev authoritydesktop/scripts/provision-dev-plugin-runner.mjs
    当前授权硬切换service/migrations/00093_remove_session_plugin_authority.sql