插件插槽补齐计划(总纲 · 跟踪 issue)
状态: 需求已在子 issue 中定稿 / 部分待定;本 issue 只做总纲与进度跟踪,具体需求、示例、契约决策以子 issue 为准。
子 issue:
本次修订(2026-09-18): 依据两个子 issue 重写。原文的「15 项 / 5 阶段 / ADR 0278–0285 / 两段式权限名 / 文件浏览器 5 槽 / 底部状态栏」等内容已过时,全部以下文为准;差异见文末「与旧稿的差异」。
1. 目标与范围
补齐 PI-Desktop 插件系统的扩展面,分两条线:
| 线 |
回答的问题 |
子 issue |
项数 |
权限前缀 |
| UI 插槽 |
插件在界面上占哪个位置 |
#545 |
14 |
ui.<域>.<项> |
| 运行时插槽 |
插件在运行时的哪个时刻被叫到、有没有决策权 |
#561 |
12 |
runtime.<域>.<项> |
同一个功能经常两边都要:位置有了但数据拿不到是空壳,数据有了但界面没位置用户看不见。排期时按"一个用户可见能力"切 PR,而不是按线切。
不在范围内(已裁定,见 #545 / #561 附录):
- 文件浏览器内的 5 个槽(右键菜单、工具栏、预览器、打开方式、装饰徽标)、工作面板 / 活动栏徽标 —— 内置面板只提供自身功能,不作为扩展点
- 底部状态栏项 —— 宿主没有这个概念
- 往会话历史写内容、替换工具实现、读凭证 / 数据目录、放松审批、改宿主自有 UI 控件、改已发生的事实
- 签名 / 分发 / 市场(ADR-0276)
尚未拆子 issue、暂不排期: 旧稿的「Provider 三件套(OCR / CLI / 受管本地服务)」与「动态模型 Provider Snapshot + OAuth + Secret Store」。它们不是插槽,属于 provider / 凭证能力,需要单独立项;本 issue 不再跟踪。
2. 总体原则(两条线共用)
- 向后兼容:只加不改。已发布的
ui.panel / ui.view / ui.theme / ui.settings / ui.microphone / ui.window.appearance 与全部旧 pi.* API 不动;manifest schemaVersion 保持 1
- 一槽一权限(D1 / D11):三段式命名;安装页逐条展示,安装 = 同意全部;升级 / 热重载新增权限才再确认(沿用
addedPermissions / beyondApproval)
- 全部走运行时注册(D6):manifest 只保留
permissions;形状与数据由插件运行时一次推出;插件没启动 / 崩溃 / 禁用 / 卸载 → 界面上根本不占位置(D10);注册失败必须在插件行 / 诊断里可见
- 宿主画外框,插件画内容(D4):弹窗 / 卡片 / 浮层的关闭、确认、取消、遮罩、层级由宿主拥有;插件最多"请求关闭";没有"撤销"概念
- 状态归宿主(D5):用户选择由宿主按 全局 / 项目 / 会话 作用域保存,插件只读 + 订阅
- 不设上限、不带版本号、通用错误(D7–D9):插件推几个显示几个;按到达顺序应用;只有成功 / 失败两态,不逐槽枚举错误码
- 位置规则(D8):插件项永远排在宿主自有项之后;窗口变窄优先隐藏插件项
- 风险分档只做展示(D2):不引入首次使用确认或默认拒绝;已有的运行时确认(剪贴板 / 出网 / 越界写 / 危险桌面操作)保持不变
- Plan / Goal 统一(D3):拒绝码沿用
PLUGIN_DISABLED_IN_PLAN
- capability 一致:主进程 capability bus 二次校验;注册 API 返回 dispose handle;Rust manifest validator 同步接受新权限名
3. UI 插槽清单(#545,D11 定稿)
| # |
插槽 |
区域 |
权限 |
风险 |
状态 |
| 1 |
消息卡渲染(Entry Renderer) |
内容区 · 整条消息 |
ui.render.message |
高 |
☐ |
| 2 |
turn / tool 卡渲染 |
内容区 · 工具卡 |
ui.render.tool |
中 |
☐ |
| 3 |
块渲染器(围栏块) |
内容区 · 代码块 |
ui.render.block |
中 |
☐ |
| 4 |
Markdown transformer(文字级) |
内容区 · 句子内部 |
ui.render.text |
中 |
☐ |
| 5 |
Composer 声明式控件槽 |
输入区 · 左 / 右 |
ui.composer.control |
低 |
☐ |
| 6 |
附件源 |
输入区 · 「+」菜单 |
ui.composer.attachment |
中 |
☐ |
| 7 |
autocomplete provider |
输入区 · 候选弹层 |
ui.composer.completion |
中 |
☐ |
| 8 |
改写草稿 |
输入区 · 输入框文字 |
ui.composer.draft |
高 |
☐ |
| 9 |
内联确认卡 |
输入框上方 |
ui.prompt.inline |
中 |
☐ |
| 10 |
全屏弹窗 |
浮层区 |
ui.prompt.modal |
高 |
☐ |
| 11 |
侧栏条目 |
外壳区 · 左侧栏 |
ui.shell.sidebar |
低 |
☐ |
| 12 |
全局浮层 |
外壳区 · 浮层 |
ui.shell.overlay |
中 |
☐ |
| 13 |
full-page workspace |
外壳区 · 整页 |
ui.shell.page |
中 |
☐ |
| 14 |
插件文案多语种 |
全局 · 插件文案 |
(无权限) |
— |
☐ |
关键前置(摘自 #545 汇总表):第 5 项需先定左右分区规则且「发送」永远最右;第 6 项需先把「+」改成菜单;第 8 项需差异对比 + 全局开关;第 11 项宿主左侧栏需先提供插件贡献位;第 13 项需路由命名空间 + 返回路径。
4. 运行时插槽清单(#561,权限名为建议,待 RD 定稿)
| # |
插槽 |
触发时机 |
权限(建议) |
现状 |
状态 |
| 1 |
发送前(Before Send) |
发送后、入队前 |
runtime.send.before |
⚙️ 内核有、桌面端没 emit |
☐ |
| 2 |
运行中观测(Turn Watch) |
本轮进行中 |
runtime.turn.watch |
🔶 只给高信任;可靠性 ❌ |
☐ |
| 3 |
中止本轮(Abort Turn) |
本轮进行中 |
runtime.turn.abort |
⚙️ Agent.abort() 未开放 |
☐ |
| 4 |
工具闸门(Tool Gate) |
工具调用前 / 后 |
runtime.tool.gate |
🔶 拦 / 改结果只给高信任;改参数 ❌ |
☐ |
| 5 |
工具能力扩展(Tool Extend) |
工具执行期间 / 返回时 |
runtime.tool.extend |
⚙️ 内核字段在、插件用不到 |
☐ |
| 6 |
请求前改写(Before Request) |
每次发模型前 |
runtime.request.before |
🔶 / ⚙️ |
☐ |
| 7 |
回合结束前(Turn Closing) ⭐ |
本轮即将结束 |
runtime.turn.closing |
⚙️ 三个入口全在、全 0 命中 |
☐ |
| 8 |
回合结束后读本轮(Turn Recap) |
一轮结束后 |
runtime.turn.recap |
❌ 桌面端明确禁了 |
☐ |
| 9 |
本轮事实查询(Turn Facts) |
一轮结束后或中途 |
runtime.turn.facts |
❌ 原料在、不开放 |
☐ |
| 10 |
宿主续跑(Turn Continue) |
一轮结束后 |
runtime.turn.continue |
⚙️ 宿主内部用了、没对外 |
☐ |
| 11 |
会话生命周期(Session Lifecycle) |
创建 / 切换 / 删除 / fork / 压缩前 |
runtime.session.lifecycle |
⚙️ 上游事件够不到 |
☐ |
| 12 |
审批前(Approval Before) |
审批卡出现前 |
runtime.approval.before |
❌ 两层都没有 |
☐ |
标记:✅ 现在就能用 · 🔶 只开给高信任插件(contributes.agentExtensions)· ⚙️ 内核有、桌面端没接线 · ❌ 要新做。
运行时待定项 RD1–RD7(阻塞第 2 / 4 / 6 / 7 / 9 / 10 / 12 项的契约):
| 编号 |
待定 |
阻塞 |
| RD1 |
插件续跑内容用户是否可见、进不进历史 |
7、10 |
| RD2 |
续跑配额(每会话 / 每轮 N 次) |
7、10 |
| RD3 |
观测可靠性分级(尽力 vs 可确认送达) |
2 |
| RD4 |
"改写"类能力的审计粒度 |
4、6 |
| RD5 |
闸门类是否先只做放行 / 拦下两态 |
4、12 |
| RD6 |
第 9 项"产物文件"的定义(artifacts 表怎么改) |
9 |
| RD7 |
高信任插件(🔶)这条路长期是否保留 |
2、4、6 |
5. 推荐执行顺序
按"一个用户可见能力 = 一个 PR"排,优先做风险低、内核已就绪、只差接线的项:
批次 A(接线为主,⚙️ 项 + 低风险 UI)
运行时 7 Turn Closing ⭐ · 运行时 1 Before Send · 运行时 3 Abort
UI 5 Composer 控件槽 · UI 11 侧栏条目 · UI 14 文案多语种
批次 B(外壳 / 提示类 UI)
UI 9 内联确认卡 · UI 10 全屏弹窗 · UI 12 全局浮层 · UI 13 整页工作区
批次 C(内容区渲染,触及 ChatTranscript.tsx hotspot)
UI 3 块渲染器 · UI 2 工具卡 · UI 4 transformer · UI 1 消息卡
批次 D(输入区,触及 Composer.tsx hotspot)
UI 6 附件源 · UI 7 补全 · UI 8 改写草稿
批次 E(需 RD 定稿后)
运行时 2 / 4 / 5 / 6 / 8 / 9 / 10 / 11 / 12
批次 A 可与 RD1–RD7 讨论并行;批次 E 在 RD 定稿前不开工。
6. 每个 PR 的交付物
- ADR:编号在开 PR 时按当时序号分配,不预留(旧稿的 0278–0285 已被其他 ADR 占用)
docs/spec/07-plugins/ 补章(UI 槽与运行时槽各一份索引章,逐槽契约按 plugin-ui-slot-contract-sample.md 格式)
packages/plugin-sdk:PLUGIN_PERMISSIONS 追加权限名 + pi.* 注册 API + schema 单测
- Rust host-core:manifest validator 接受新权限名(纯运行时注册,不新增
contributes.* 字段)
- 主进程:registry + capability bus 校验 + dispose
- Renderer:outlet 组件放
apps/desktop/src/plugins/renderer-slots/;hotspot 文件只加 outlet
- agent-runtime(运行时槽):接线到内核入口,审计落 host-core
- 至少 1 个
examples/plugins/ 示例插件,可 pnpm plugin:install 装入 dev 桌面
- 测试:SDK schema + plugin-runtime integration + renderer 组件 + Rust validator;
verify:ui:* 不跑除非用户显式要求
packages/plugin-sdk/README.md API 目录 + 07-plugins/14-plugin-roadmap.md 更新
通用验证:
pnpm build:js
pnpm --filter @pi-desktop/desktop typecheck
pnpm lint
pnpm -r --if-present test
cargo fmt --check && cargo test -p host-core --locked && cargo clippy -p host-core --all-targets
pnpm check:agent-policy
7. 风险与缓解
| 风险 |
缓解 |
| ChatTranscript.tsx / Composer.tsx hotspot |
只加 outlet,逻辑放 renderer-slots/;单 PR 净增 ≤ 150 行 |
| 数量不设上限(D8)导致界面拥挤 |
位置规则:插件项排在宿主项后,窄窗口优先隐藏;用户可禁用 |
| 高风险槽(消息卡 / 改写草稿 / 全屏弹窗)装上即生效 |
安装页显眼展示风险档;契约写死宿主强制边界;随时禁用 |
| 运行时"改写"类能力不可解释 |
RD4 定审计粒度前不做改写;先只做两态(RD5) |
| 续跑无上限循环 |
RD2 定配额前不开放续跑 |
| 插件崩溃留下可点却必失败的控件 |
硬边界 2:插件消失后已渲染实例进入不可交互态 |
| harness 层 11 个钩子自带持久化,与 host-core 独占持久化冲突 |
要用先出 ADR |
8. 完成判据
与旧稿的差异(2026-09-18)
| 旧稿 |
现在 |
| 15 项、5 阶段、8 个 ADR(0278–0285) |
14 项 UI + 12 项运行时;ADR 编号不预留(0278–0281 已被占用) |
两段式权限名 ui.statusBar / ui.badge / ui.sidebar / ui.workspacePage / ui.overlay |
三段式 ui.<域>.<项>(D11);状态栏、徽标已裁掉 |
contributes.* 声明 + pi.* 动态注册 三段式 |
只走运行时注册,manifest 只留 permissions(D6) |
| 阶段 2 文件浏览器 5 槽 |
裁定不做 |
| 阶段 3 Provider 三件套、阶段 4 OAuth / Secrets |
不属于插槽,移出本 issue,需单独立项 |
| Sidebar 项目 / 会话列表条目、view badge |
侧栏条目保留(第 11 项);badge 裁掉 |
| overlay 并发 ≤ 3、badge 节流 |
数量不设上限(D8) |
| 未提运行时时机 |
新增 #561 的 12 项运行时插槽与 RD1–RD7 |
插件插槽补齐计划(总纲 · 跟踪 issue)
1. 目标与范围
补齐 PI-Desktop 插件系统的扩展面,分两条线:
ui.<域>.<项>runtime.<域>.<项>同一个功能经常两边都要:位置有了但数据拿不到是空壳,数据有了但界面没位置用户看不见。排期时按"一个用户可见能力"切 PR,而不是按线切。
不在范围内(已裁定,见 #545 / #561 附录):
尚未拆子 issue、暂不排期: 旧稿的「Provider 三件套(OCR / CLI / 受管本地服务)」与「动态模型 Provider Snapshot + OAuth + Secret Store」。它们不是插槽,属于 provider / 凭证能力,需要单独立项;本 issue 不再跟踪。
2. 总体原则(两条线共用)
ui.panel/ui.view/ui.theme/ui.settings/ui.microphone/ui.window.appearance与全部旧pi.*API 不动;manifestschemaVersion保持1addedPermissions/beyondApproval)permissions;形状与数据由插件运行时一次推出;插件没启动 / 崩溃 / 禁用 / 卸载 → 界面上根本不占位置(D10);注册失败必须在插件行 / 诊断里可见PLUGIN_DISABLED_IN_PLAN3. UI 插槽清单(#545,D11 定稿)
ui.render.messageui.render.toolui.render.blockui.render.textui.composer.controlui.composer.attachmentui.composer.completionui.composer.draftui.prompt.inlineui.prompt.modalui.shell.sidebarui.shell.overlayui.shell.page关键前置(摘自 #545 汇总表):第 5 项需先定左右分区规则且「发送」永远最右;第 6 项需先把「+」改成菜单;第 8 项需差异对比 + 全局开关;第 11 项宿主左侧栏需先提供插件贡献位;第 13 项需路由命名空间 + 返回路径。
4. 运行时插槽清单(#561,权限名为建议,待 RD 定稿)
runtime.send.beforeruntime.turn.watchruntime.turn.abortAgent.abort()未开放runtime.tool.gateruntime.tool.extendruntime.request.beforeruntime.turn.closingruntime.turn.recapruntime.turn.factsruntime.turn.continueruntime.session.lifecycleruntime.approval.before标记:✅ 现在就能用 · 🔶 只开给高信任插件(
contributes.agentExtensions)· ⚙️ 内核有、桌面端没接线 · ❌ 要新做。运行时待定项 RD1–RD7(阻塞第 2 / 4 / 6 / 7 / 9 / 10 / 12 项的契约):
artifacts表怎么改)5. 推荐执行顺序
按"一个用户可见能力 = 一个 PR"排,优先做风险低、内核已就绪、只差接线的项:
批次 A 可与 RD1–RD7 讨论并行;批次 E 在 RD 定稿前不开工。
6. 每个 PR 的交付物
docs/spec/07-plugins/补章(UI 槽与运行时槽各一份索引章,逐槽契约按plugin-ui-slot-contract-sample.md格式)packages/plugin-sdk:PLUGIN_PERMISSIONS追加权限名 +pi.*注册 API + schema 单测contributes.*字段)apps/desktop/src/plugins/renderer-slots/;hotspot 文件只加 outletexamples/plugins/示例插件,可pnpm plugin:install装入 dev 桌面verify:ui:*不跑除非用户显式要求packages/plugin-sdk/README.mdAPI 目录 +07-plugins/14-plugin-roadmap.md更新通用验证:
7. 风险与缓解
renderer-slots/;单 PR 净增 ≤ 150 行8. 完成判据
PLUGIN_PERMISSIONS新增 13 个ui.*+ 12 个runtime.*,Rust validator 同步docs/spec/07-plugins/README.md索引与14-plugin-roadmap.md更新与旧稿的差异(2026-09-18)
ui.statusBar/ui.badge/ui.sidebar/ui.workspacePage/ui.overlayui.<域>.<项>(D11);状态栏、徽标已裁掉contributes.*声明 +pi.*动态注册 三段式permissions(D6)