编写规范(CORE)

August 14, 2026 · View on GitHub

本文件是 CORE 项目所有动态插件代码的强制性约定。

1. 语言与转换

  • code.host / code.client纯 JavaScript 函数体,不经过 TS / JSX / bundler 转换。
  • 禁用:importrequire、TypeScript 类型 / as / 装饰器、JSX。
  • Client React 一律 React.createElement(type, props, ...children)
  • 不要假定 processBufferwindowdocumentfetchsetTimeout 等全局存在 —— 先查对应平台的 Builtins / Service。

2. 服务访问

  • 可选服务:const s = ctx.get('name'),然后判 undefined
  • 硬依赖:return { inject: ['name'], apply(ctx) { ctx.name.… } } —— 仅在服务缺失时应让插件进入等待(Cordis 会在服务出现后重新激活)时才用。
  • 未声明 inject 就访问 ctx.name 会被 Guard 拒绝。

3. 生命周期与副作用

  • 一切副作用(Service / Event / Tool / 定时器 / Slot / 样式 / 主题层)必须归属当前 Fiber,stop / update / undefine 时自动清除。
  • 首选 ctx.effect(() => disposer)ctx.on(...) 或官方 API 返回的 disposer。
  • 模块作用域与 apply() 之外不允许产生进程级 / 页面级副作用。
  • 定时器是 Service timer(Host/Client 同构):inject: ['timer'] 后可用 ctx.timeout / ctx.interval / ctx.throttle / ctx.debounce

4. 活数据守则

  • Service 实例、Event payload、Slot props、Session / ConversationSnapshot、Tool 状态是内部活数据
  • 禁止:JSON.stringify / structuredClone / 递归枚举 / 整体复制 / 整体渲染。
  • 只取任务需要的叶子字段,再构造最小的自有 JSON。

5. 平台选择

需求平台
文件 / 命令 / 进程 / 网络Host(fs / shell / subprocess / web)
Agent / Session / Host 生命周期Host
注册模型可调用的 ToolHost(harness)
页面主题 / 布局 / 当前页面状态Client
会话快照 / 会话列表 / 工作区列表Client(槽位 props 已提供)
设置页 / 侧栏 / 输入区 / 浮层 / Tool 卡Client(Slots)
Host 取数 + Client 展示双半(harness.handle + host.call)

优先选择离数据最近的能力:槽位 props 已有的会话快照不要再经 Host 拉一遍;只改本包样式就别覆盖全局主题;只要小入口就别替换整块产品 UI。

6. Host ↔ Client RPC(包私有)

  • Host:harness.handle(method, handler);handler 入参 / 返回值必须是 lossless JSON。
  • Client:host.call(method, args),返回 Promise。
  • 方向固定 Client→Host;禁止把函数 / React 元素 / Service / Context 等运行时对象传过线,无数据返回 null
  • 这是包私有通道;不要注册公开 Remote Service 或用 ctx.remote

7. 动态 Tool(Host)

必须经 harness.defineTool 产出、harness.registerTool(ctx, tool) 注册(属于当前 Fiber,随 Run 自动移除):

harness.registerTool(ctx, harness.defineTool({
  name: 'core_demo',
  description: '一句话描述。',
  parameters: { text: { type: 'string', required: true } },   // ParameterSchemaSpec DSL
  output: {
    schema: { type: 'string' },                               // execute 返回值的 JSON schema
    render(_args, value) { return [{ type: 'text', text: String(value) }] },
    // presentationMeta 可选
  },
  async execute(args) { return 'ok' },                        // 返回值经 JSON 往返归一
}))
  • 注册前用 Tool.listTools 查重,避免与现有工具冲突。
  • execute 拥有业务结果;render 只决定模型与原生 UI 看到什么。
  • 工具参数与返回值必须 JSON 兼容;注册必须属于当前 Plugin Fiber。

8. 版本与审批

  • 改代码 = 追加新 Package;永远不覆盖旧版本
  • 审批:单勾 = 只授权当前 Package;双勾 = 授权同插件未来版本。技术失败不撤销授权。
  • 用户拒绝审批后不得自动重试。

9. 运行与恢复

当前状态目标mode
无 current任意 Packagerun
有 current同一个 Packagerun
有 current不同 Packageupdate
update 失败nextPackageIdupdate 重试
update 失败currentPackageIdrun 回滚
  • cordis_run 返回 awaiting-approval / starting不代表成功;本轮结束,等系统上报。
  • 技术失败:cordis_inspect_self(pluginId, packageId) 读源码与诊断 → 修复 → 同插件追加 Package → 重试。不要另建同名插件。
  • update 失败不会自动恢复旧 Run;需要回滚时显式 run current。

10. 常见失败速查

现象先查
service "x" is not declared是否未声明 inject: ['x'] 就用了 ctx.x → 改 ctx.get('x') 或缺省处理 / 声明硬依赖
cannot get property "timer" without inject声明 inject: ['timer']
Client 解析失败是否用了 JSX / TS / import / 不存在的全局
槽位注册失败是否查过活槽位树;选项、key、selector 是否满足返回的协议
UI 加载但页面报错cordis_inspect_selfclient-render 诊断与堆栈
host.call 失败方法名、当前 pluginRunId、JSON 参数、handler 内的真实服务依赖
update 失败保持 current/next 语义:修复 next 后 update,或 run current 回滚