Skip to content

docs: plugin host architecture design - #2222

Open
Can2Nya wants to merge 1 commit into
GCWing:mainfrom
Can2Nya:plugin_host_docs
Open

docs: plugin host architecture design#2222
Can2Nya wants to merge 1 commit into
GCWing:mainfrom
Can2Nya:plugin_host_docs

Conversation

@Can2Nya

@Can2Nya Can2Nya commented Aug 11, 2026

Copy link
Copy Markdown

Summary

  • 将 Plugin Host 架构设计从代码实现 PR 中拆分为独立文档变更。
  • 新增 BitFun 集成 OpenCode Extension Host 的完整架构设计。
  • 新增 Plugin Client 到 Rust Backend 的 HTTP/RPC 路由适配设计。
  • 更新 OpenCode Extension 兼容性文档的架构索引。
  • 更新贡献指南,补充 CLI Plugin Host 资源检查说明。

Type and Areas

Type: docs

Areas: Rust core architecture, CLI/plugin host, OpenCode extension compatibility

Motivation / Impact

本 PR 将插件 Host 相关设计文档与运行时代码拆分,便于独立评审和后续维护。

文档覆盖以下内容:

  • Plugin Host 的启动条件、运行时选择和配置格式。
  • Bun/Node Host 的进程拓扑和 Backend/Host 的 1:1 关系。
  • IPC 连接认证、Frame 协议和双向可重入 JSON-RPC。
  • Workspace、Session 和 Plugin Instance 生命周期。
  • Plugin Host 优雅关闭、请求等待、超时和强制退出策略。
  • Plugin Host 日志目录、日志级别和故障诊断方式。
  • input.client.*backend.http.request 的调用链路。
  • Rust HTTP 路由表、响应流、实例隔离、目录安全和错误映射。
  • OpenCode Client 全量 API 的 Rust 支持矩阵。
  • 明确暂不适配的 P/D 能力,以及 Event、Auth、Instance、Permission、TUI 等类别。

当前文档基线以 @opencode-ai/sdk@1.17.18 为准:

  • A 类路由:作为当前可适配能力记录。
  • P/D 类路由:明确记录为暂不注册或降级处理。
  • pty.connect()、WebSocket、事件流、认证、TUI 等能力:不在本阶段适配范围内。

对应运行时代码实现位于配套 PR:

Verification

  • git diff --check origin/main...HEAD
  • 手动检查文档路径、内部链接和目录归属。
  • 确认文档 PR 不包含 Rust、TypeScript 或运行时实现变更。
  • 未运行 Cargo 或 Host 测试,因为本 PR 仅包含架构文档和贡献指南更新。

Reviewer Notes

  • 主要设计文档:
    • docs/architecture/extensions/bitfun-opencode-ext-host-ipc-design.md
    • docs/architecture/extensions/opencode-plugin-client-route-adapter-design.md
  • 本 PR 与代码实现 PR feat: integrate managed opencode plugin host #2221 分离,建议先独立评审架构边界,再结合代码 PR 验证实现一致性。
  • 文档中的 A/P/D 支持矩阵用于描述当前实现边界,不代表所有 OpenCode API 都已实现。
  • 文档明确禁止通过通用 HTTP Proxy 暴露未登记的 OpenCode 路由。
  • 文档未保留独立的 Node Host 设计文档,Node/Bun Host 的差异统一维护在 IPC 架构文档中。

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above.
  • User-facing strings, docs, and locales are updated where applicable.

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议暂缓合并。这个 PR 对进程启动、IPC 和关闭流程写得比较细,但几个更上层的边界还需要先定清楚,否则实现后很容易出现两套插件运行机制并存、OpenCode 接口反向侵入 BitFun 核心模块,以及插件权限和崩溃恢复无法闭环的问题。

以下意见只保留与当前设计直接相关的架构问题。

[P1] 不要绕过现有插件运行入口,另建第二套

问题

bitfun-opencode-ext-host-ipc-design.md:118-140,743-765 让 Core 和 Session 直接持有、调用 HostClientopencode-plugin-client-route-adapter-design.md:192-209 又准备在 Core/Assembly 增加 PluginHostBackendBridge 和实例状态。

但仓库已经有统一的 PluginRuntimeClient。如果 Core 可以直接调用 Host,就会同时存在两条插件执行路径。

风险

两条路径会分别处理插件启停、超时、取消、崩溃恢复、权限检查和结果发布。Desktop、CLI、Remote 后续也可能各走各的入口,最终很难判断哪一套状态才是真的。

建议

产品模块只能调用 PluginRuntimeClient

产品功能模块
  -> PluginRuntimeClient
  -> OpenCode 适配层
  -> 进程服务
  -> 一个 Plugin Host
  -> 一个或多个插件执行进程

Assembly 只负责选择和注入实现;OpenCode 格式转换留在 OpenCode 适配层;Host 及其下属插件进程的启动、连接和回收留在 services。插件执行进程返回的工具、Hook 等内容还要交给真正的功能模块校验后再生效,不能由 Host 或 Assembly 直接注册。

完成标准

  • Core/Assembly 不直接持有 HostClient 或 Host 实例表。
  • Desktop、CLI、Remote 都只能通过同一个插件运行入口调用。
  • 插件启停、权限和恢复状态各自只有一个明确负责人。

[P1] 不要把 OpenCode 的整套 HTTP 接口变成 BitFun 内部总入口

问题

opencode-plugin-client-route-adapter-design.md:54-69,192-209,340-403 计划通过一个 backend.http.request,把 OpenCode SDK 请求分发到 Workspace、Session、文件、终端、Git、MCP、LSP、配置和模型供应商等大量 BitFun 模块。

文档虽然说这不是完整 OpenCode Server,但如果 Core 需要理解并分发这么多 OpenCode HTTP 路径,实际上仍然是在 Core 中建立一层“精简版 OpenCode Server”。

风险

OpenCode 一旦改接口,BitFun 多个核心模块都可能跟着改;其他插件生态也可能照此再建一套总入口。长期会出现多套外部协议直接穿透 Core,各功能模块原有的权限、取消和状态管理被绕开。

建议

只实现真实插件已经使用、并且有固定样例验证的 Client 接口。HTTP method、path 和 OpenCode DTO 都留在 OpenCode 适配层;适配层再调用各功能模块已有的窄接口,不要定义一个覆盖所有服务的通用 BackendCapability

这里的 1.17.18 只需要被说明为“当前内嵌 SDK 和路由表的参考版本”。现有其他文档使用 1.18.4/1.18.9,应说明它们分别是历史审计快照还是当前实现依据,但没有必要为了尚未提出的多版本兼容设计复杂的版本协商。

完成标准

  • OpenCode 路由变化不会迫使无关 Core 模块修改公共接口。
  • 每条开放路由都有真实插件样例和端到端测试。
  • 未验证路由明确返回不支持,而不是先铺完整 SDK 路由表。
  • 文档明确 1.17.18 的作用范围,并处理与其他参考版本的表述冲突。

[P1] 配置里写了插件,不等于已经允许执行

问题

bitfun-opencode-ext-host-ipc-design.md:145-164,497-523,676-739 把全局 app.json.plugin 非空作为启动 Host、导入插件和打开工作区插件实例的主要条件。

配置只能说明“用户或项目声明了这个插件”,不能直接证明“当前这份代码已经被允许在这个位置执行”。

风险

用户确认之后,本地文件或 npm 包内容可能已经变化;应用重启时也可能从同一路径加载到不同内容。远程工作区还可能错误沿用本机的确认结果。

建议

把两个步骤明确分开:

  1. 从配置中发现插件;
  2. 在执行前确认插件来源、当前实际内容、运行位置和权限仍然符合用户之前的决定。

Host 只能接收已经通过第二步检查的插件清单,不能自己根据原始 app.json 判断是否可以执行。重启、插件更新、切换到远程环境时都要重新检查当前内容和执行位置。

完成标准

  • 没有有效执行许可时,不能启动 Host 或导入插件代码。
  • 插件内容、运行位置或权限变化后,旧许可不能继续使用。
  • 本地和远程环境分别判断,不允许远程失败后偷偷回到本机执行。

[P1] 明确 Host 和插件执行进程的关系,不要把两层混成一层

问题

一个 backend 对应一个 Host 是合理的:它可以统一管理连接、插件清单、请求转发、日志和关闭流程,也能避免每个工作区重复创建管理进程。

但当前文档没有把“管理 Host”和“真正运行插件代码的进程”分开。bitfun-opencode-ext-host-ipc-design.md:89-116,442-486,676-739 把一个 backend 对应到一个选定的 Node/Bun Host,并把多个插件声明直接交给这个 Host;现有通用设计也把 Plugin Host 定义成“直接加载并运行第三方插件代码的进程”。这与“一个 Host 管理多个插件执行进程”是两种不同的进程结构。

风险

如果按当前文字实现,所有插件仍会在唯一 Host 进程内执行。一个插件的死循环、内存耗尽或主动退出就会带走全部插件;Node/Bun 也只能在整个 backend 级统一选择。

反过来,如果实现人员自行在 Host 下增加多个插件进程,却没有文档规定谁启动、停止和回收它们,又会产生无人负责的子进程和不一致的恢复流程。

建议

明确采用下面的两层结构:

BitFun backend
  -> 一个 Plugin Host:统一管理连接、插件清单、请求转发、日志和关闭
     -> 多个插件执行进程:真正导入并运行第三方插件代码

一个 Host 管理多个执行进程即可,不必现在写死“一个插件一个进程”。运行环境相同、可以安全共享的插件可以共用执行进程;需要不同 Node/Bun 环境、远程位置或隔离条件时再拆开。

services 仍应掌握完整进程树,确保 backend 或 Host 退出时可以回收所有插件进程。Node/Bun 的选择如果是插件代码的运行要求,应放在插件执行进程这一层,而不是由唯一 Host 全局决定。

完成标准

  • 文档明确 Host 是管理进程,插件代码由下层执行进程运行。
  • 一个插件执行进程崩溃时,只撤下受影响插件,不必让所有插件失效。
  • Host 崩溃时,Rust 将其管理的全部插件进程一起标记失效并统一恢复。
  • backend 退出时,所有插件进程都能由受监督的进程树完整回收。

[P1] 如果要做“按插件授权”,请求里就必须知道是哪个插件发起的

问题

opencode-plugin-client-route-adapter-design.md:78-85 的请求只有 instance、请求编号、HTTP 方法和路径;:303-315 保存的也只是工作区和一份统一权限,没有插件身份。

但同一个工作区实例会加载多个插件。当前协议无法判断某个文件、终端或 Session 请求究竟来自哪一个插件。

风险

如果不同插件应有不同权限,一个插件就可能使用另一个插件获得的权限;日志也无法回答“是谁执行了这次操作”,撤销单个插件的权限同样无法立即生效。

建议

Host 给每个插件创建独立的 Client,请求由 Host 自动附带真实插件身份、当前插件内容版本和当前权限版本,不能让插件自己通过 header 声明身份。Rust 收到请求后,再根据该身份检查权限。

如果产品决定所有插件完全共享权限,也可以不做上述隔离,但文档就不应再承诺“按插件检查权限和审计”。两种模型需要明确选一个。

完成标准

  • 能确认每个请求来自哪个插件。
  • 两个插件可以拥有不同权限和独立审计记录。
  • 禁用一个插件后,它不能继续借用旧请求或旧权限调用后端。

[P1] Host 崩溃后,旧能力必须整体撤下,再整体恢复

问题

bitfun-opencode-ext-host-ipc-design.md:813-820 规定 Host 丢失后实例失效,并在后续工作区操作时重新启动、重新打开实例,但没有说明旧的工具和 Hook 何时撤下、多个工作区是否一起恢复,以及恢复一半失败时产品应处于什么状态。

风险

可能出现旧工具仍显示可用但实际 Host 已经死亡,或者部分工作区使用新 Host、部分仍保留旧状态。对于删除、更新、执行工具等操作,如果请求已经送出但响应在崩溃时丢失,简单返回“连接断开”还可能诱导调用方重复执行。

建议

Host 崩溃后应按一个完整流程处理:先停止接收新调用,取消或等待旧调用,撤下该 Host 提供的全部工具和 Hook,启动新 Host,重新加载所有仍在使用的工作区,全部校验成功后再一次性恢复可用状态。中间任一步失败,就保持不可用,不能留下半新半旧状态。

对于已经发出但不知道是否执行成功的写操作,应返回清楚的“结果未知”,禁止自动重试,由真正保存状态的模块重新查询结果。

完成标准

  • 单个插件执行进程崩溃时只影响对应插件;Host 崩溃时,其管理的全部插件一起失效、一起恢复。
  • 恢复完成前旧工具和 Hook 不再可见,也不接收新调用。
  • 任一工作区恢复失败时不会发布一半的新状态。
  • 写操作丢失响应时不会自动重复执行。

以上问题都来自当前文档已经提出的生产路径,不依赖 OpenCode v2 或假设未来一定支持多版本。建议先把这些边界修正,再继续补充路由和进程实现细节。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants