启航插件 API v1

开发者面向启航 Code 编写插件时唯一需要遵守的接口。DSH 内核升级由平台适配层消化,插件代码不修改、用户不重装。

版本 v1.0-draft 适用客户端 1.0.x 适配内核 DSH 0.1.5-rc.2 ~ 0.2.x 2026-10-22

1文档定位

这份文档定义开发者面向启航 Code 写插件时唯一需要遵守的接口,不描述 DSH 内部机制。

核心承诺:开发者只依赖《启航插件 API v1》。DSH 内核升级由平台的兼容垫片消化,插件代码不修改、用户不重装。

要兑现这个承诺,插件与 DSH 之间必须有一层受控边界。当前代码里已有运行时适配层,但开发者 API 层尚未建立,自有插件仍直接调用 DSH 的插槽与词典内部结构。本文档即该 API 层的契约定义。

2三层架构与职责边界

插件(开发者代码)
  只允许 import '@qicode/plugin-sdk'
        │ 稳定契约(本文档)
L2 启航插件 SDK
  生命周期 / UI 扩展点 / 宿主服务 / 权限
        │ 每个 DSH 版本一份实现
L3 兼容垫片 Compat Shim
  SDK 调用 → DSH slots / locale / 宿主服务
        │
L1 运行时适配层(已具备)
  内核版本校验 / profile 生成 / 依赖链接 / 启动 / IPC / 窗口
  • L1 不感知插件业务,只负责把 DSH 以正确形态跑起来。
  • L2 是对外唯一契约,版本号独立于 DSH,遵循语义化版本。
  • L3 允许随 DSH 升级重写,是唯一允许接触 DSH 内部结构的层。
  • 插件不得越过 L2 直接访问 DSH。

3插件包结构与 Manifest

3.1 包结构

my-plugin/
├── package.json          # 含 qicode 字段
├── dist/
│   ├── host.js           # 主机端入口(Node 侧,可选)
│   └── client.js         # 界面端入口(浏览器侧,可选)
├── README.md
└── icon.png              # 128×128,市场展示用

包格式与 npm 一致(.tgz),便于复用现有 registry 与缓存机制。

3.2 Manifest 示例

{
  "name": "@qicode/plugin-example",
  "version": "1.0.0",
  "description": "示例插件",
  "qicode": {
    "apiVersion": "1",
    "id": "com.blokeai.example",
    "displayName": "示例插件",
    "publisher": "朔序科技",
    "system": false,
    "entry": { "host": "./dist/host.js", "client": "./dist/client.js" },
    "engines": { "qicode": ">=1.0.0 <2.0.0" },
    "permissions": ["storage", "net.outbound"],
    "network": { "allow": ["api.blokeai.com"] }
  }
}
字段必填说明
apiVersion是固定为 "1",SDK 大版本
id是全局唯一,反向域名。官方保留 com.blokeai.*
displayName是市场与插件列表展示名
publisher是发布者名称,签名主体需一致
system否true 表示核心组件,不可禁用、不可卸载
entry.host二选一主机端入口,ESM
entry.client二选一界面端入口,ESM
engines.qicode是兼容的 SDK 版本区间,安装时校验
permissions是权限清单,见第 7 节
network.allow否联网白名单,仅 net.outbound 生效

4生命周期

export interface QicodePlugin {
  activate(ctx: QicodeContext): void | Promise<void>;
  deactivate?(): void | Promise<void>;
}
阶段时机约束
解析客户端启动,读取已安装清单校验 manifest、签名、SDK 版本区间
激活DSH 就绪后按依赖顺序调用单插件超时 10s;失败不阻塞其他插件
运行注册扩展点、注册工具所有资源必须挂在 ctx 上,随停用释放
停用用户禁用 / 卸载 / 退出deactivate 超时 3s 后强制回收
失败隔离激活或运行抛错标记为“异常”,界面提示,不白屏

崩溃保护:同一插件连续 3 次激活失败,自动置为“已禁用”并在插件页提示,需用户手动恢复。

4.1 与 DSH cordis 生命周期的映射

插件不实现 cordis 的 apply / inject,由 L3 垫片完成翻译:

SDK 概念DSH cordis 对应实现说明
activate(ctx)垫片导出的 apply(ctx)异步 activate 由垫片包装,DSH 启动不被阻塞
deactivate()apply 返回的 disposer / ctx.effect 回收先调用插件 deactivate,再释放扩展点与工具
manifest permissions垫片内的能力校验开发者不写 inject 数组,服务按权限注入
ctx.tools.registerdefineTool + ctx.tools.register工具定义按 SDK 归一化后透传
ctx.ui.*ctx.slots.inject/register声明式扩展点翻译为具体槽位
ctx.storage/config/secretsprofile 目录 + 主进程密钥服务按插件 id 隔离

边界:activate 内抛错不会导致 DSH 启动失败;垫片捕获后标记插件异常,其余插件继续激活。

5UI 扩展点

插件不写 DOM、不写 CSS 选择器、不依赖官方类名。所有界面接入通过声明式扩展点完成。

5.1 API

ctx.ui.brand({ mark?: Component, name?: Component | string });

ctx.ui.headline({ zh: string, en: string });

ctx.ui.sidebarItem({ id, title, icon, order, onOpen: () => void });

ctx.ui.sidebarFooterAction({ id, title, icon, onClick });

ctx.ui.page({ id, title, component, placement: 'main' | 'right-pane' });

ctx.ui.composerDock({ id, component, order });

ctx.ui.settingsSection({ id, title, component });

ctx.ui.messageAction({ id, title, onClick, when: 'assistant' | 'user' });

5.2 与当前 DSH 槽位的映射(L3 内部实现,插件不感知)

SDK 扩展点当前实现槽位稳定性
ui.brandsidebar.brand.mark / sidebar.brand.name / conversation.hero.brand.mark稳定
ui.headlineconversation 词典 hero.headline稳定
ui.sidebarItemsidebar.panellist(list,条目参数 id / order / label / locale)稳定
ui.sidebarFooterActionsidebar.footer.action(list)稳定
ui.settingsSectionsettings.general.item稳定
ui.messageActionconversation.chat.assistant-actions稳定
ui.composerDockconversation.input.dock稳定
ui.page主面板:ctx.layout 面板注册 + sidebar.panellist 条目;右侧:sidebar.right.pane.tabBeta

约定:ui.sidebarItem 与 ui.page 必须成对使用,条目 id 即面板 id。标注 Beta 的扩展点允许在 SDK 次版本内调整参数,需在变更日志中提前一个版本公告。

6宿主服务

ctx.log.info / warn / error(msg, meta?)

ctx.storage.get(key) / set(key, value) / delete(key) / list()

ctx.config.get() / ctx.config.onChange(fn)

ctx.session.current() / list() / read(id)
ctx.session.onEvent(fn)

ctx.model.invoke({ messages, model?, temperature? })

ctx.fs.readText(path) / writeText(path, content) / pick({ mode })

ctx.net.fetch(url, init?)

ctx.tools.register(toolDef)

ctx.secrets.get(name)
  • 所有异步 API 必须支持 AbortSignal(ctx.signal),插件停用时自动中止。
  • ctx.model.invoke、ctx.net.fetch、ctx.secrets.get 计入用量与审计日志。
  • 不允许插件直接 require('electron')、访问 window.blokeai 或 Node 原生 fs/net/child_process。

7权限模型

权限能力用户可见提示
storage插件私有键值存储无
fs.read读取工作区文件首次使用时授权
fs.write写入工作区文件首次使用时授权
net.outbound访问 manifest 白名单域名安装时列出域名
model.invoke调用平台模型消耗用户配额,明确提示
session.read读取会话内容安装时提示
secrets读取平台托管密钥单独二次确认
process.exec执行本地命令默认拒绝,需企业策略放开

权限在安装时展示,运行期由 L3 强制校验,插件无法自行提权。权限变更(新增)需重新授权。

8错误处理与降级

  • 插件异常不得导致主界面白屏:L3 为每个插件包裹错误边界。
  • UI 组件抛错时渲染占位块,并提供“禁用此插件”入口。
  • 宿主服务调用失败返回结构化错误 { code, message, retryable },不抛裸异常。
  • 插件日志统一写入 plugin-data/<id>/logs/,滚动保留 7 天。

9兼容与弃用策略

  1. 版本独立:SDK 版本(apiVersion)与 DSH 版本解耦。DSH 升级只改 L3。
  2. 兼容垫片按 DSH 次版本维护:每个 DSH 次版本对应一份 shim,附契约测试用例。
  3. 契约测试:每次升级 DSH 前自动运行,覆盖品牌位、扩展点挂载、工具注册、词典改写、插件启停。
  4. 弃用窗口:任何 SDK API 删除前,至少保留两个次版本的过渡期,并在启动时输出弃用警告。
  5. 紧急熔断:服务端可下发插件黑名单与最低 SDK 版本,客户端启动时拉取并生效。
  6. 回滚:新版本插件加载失败自动回退上一可用版本。

10禁止条款

插件发布时静态扫描,命中即拒绝上架:

禁止项检测方式
import / require 任何 @deepseek-ai/* 包AST 扫描依赖与源码
DOM 查询与样式注入(querySelector、style 注入)AST + 字符串规则
读取 DSH 词典内部结构(locale.dicts)AST 规则
直接访问 window.blokeaiAST 规则
未声明权限却调用对应宿主能力运行时拦截 + 静态校验
打包内含原生二进制且未声明包内容扫描

11现状接口盘点(截至 2026-10-22)

11.1 已具备的运行时适配能力(L1)

能力实现位置判定
DSH 版本读取与兼容区间校验electron/dsh-adapt.js稳定
旧插件公共包链接(9 个)electron/dsh-adapt.js稳定,随 DSH 大版本复核
适配结果落盘 .qicode-compat.jsonelectron/dsh-adapt.js稳定
profile 生成(bundles、patchReload、用户补丁层)electron/main.js稳定
自有插件链接/复制到 profileelectron/main.js稳定
DSH 子进程启动、端口清理、孤儿锁自愈electron/main.js稳定

11.2 渲染进程桥

window.blokeai 当前暴露 22 个方法:设置读写、登录鉴权、支付下单与轮询、外链、关于页、退出、版本号等。判定:内部接口,不对插件开放。SDK v1 另建权限受控的能力桥。

11.3 插件现有接入方式与稳定性判定

机制现状判定
主机端入口 apply(ctx) + injectqicode-dsh-kit/lib/index.js可用,需包装为 SDK 生命周期
工具注册 ctx.tools.register同上稳定,纳入 ctx.tools
界面端 window.__ModuleLoader__.loadqicode-dsh-kit/lib/client.js无版本契约,需由 L3 封装
插槽注册 ctx.slots.inject/register品牌位、插件页标签稳定,插件不再直接调用
词典内部改写 locale.dicts首屏标语覆盖临时
插件页开关守卫(DOM 注入)injectPluginGuard技术债
设置页标题修正(DOM 注入)injectSettingsTitleFix技术债
标题栏菜单注入(DOM)injectTitleBarMenu技术债

11.4 缺口清单

  1. 无 @qicode/plugin-sdk 包,无统一上下文对象。
  2. 无 manifest 规范落地与安装期校验。
  3. 无签名、无校验和、无私有 registry。
  4. 无扩展点声明式 API,现有插件直接写 DSH 槽位。
  5. 无权限模型与能力桥。
  6. 无插件启停隔离、超时回收、崩溃熔断。
  7. 无契约测试,DOM 补丁未迁移。

12参考实现:qicode-dsh-kit 改造前后

改造前(直接依赖 DSH)

window.__ModuleLoader__.load({
  id: 'qicode-dsh-kit/client',
  factory: (require) => {
    var React = require('react');
    function apply(ctx) {
      ctx.slots.inject('sidebar.brand.mark', function* () {
        yield ctx.slots.register({ name: 'sidebar.brand.mark', priority: -10 }, Mark);
      });
    }
    return { apply, inject: ['slots', 'locale'] };
  }
});

改造后(只依赖 SDK)

import { definePlugin } from '@qicode/plugin-sdk';
import { BrandMark } from './brand.js';

export default definePlugin({
  id: 'com.blokeai.core-kit',
  system: true,
  activate(ctx) {
    ctx.ui.brand({ mark: BrandMark, name: '启航 Code' });
    ctx.ui.headline({ zh: '启新朔 · 定万序', en: 'Set Sail · Shape the Order' });
    ctx.tools.register(supportTool);
  }
});

system: true 由 L3 强制执行:插件页不显示开关,配置层无法禁用,启动时自动恢复。

13里程碑

阶段交付物验收标准
M1本文档冻结 + manifest JSON Schema评审通过,Schema 可校验
M2@qicode/plugin-sdk 骨架(host + client)示例插件跑通生命周期
M3qicode-dsh-kit 迁移为 SDK 插件品牌/标语/工具与现版本行为一致
M4L3 兼容垫片 + 契约测试DSH 升级后插件零改动
M5私有 registry + 签名 + 安装校验全链路打通,篡改包被拒绝
M6客户端内插件市场 UI列表、详情、安装、更新、回滚

14变更记录

版本日期内容
v1.0-draft2026-10-22初稿:三层架构、manifest、扩展点、宿主服务、权限、现状盘点