第 10 章:多端 UI —— TUI、Web、Desktop、ACP 共享同一后端语义¶
1. 多端不是复制业务逻辑¶
OpenCode 当前包含 packages/tui 终端界面、packages/app 应用 UI、packages/web 官网与文档、packages/desktop Electron 宿主、packages/cli / packages/opencode 命令入口,以及共享的 session-ui 和 ui 包。
它们共享的是 SDK / HttpApi / Event / Schema,不是直接共享 server service。这样每个宿主可以有自己的渲染技术和生命周期,同时保留一致的 Session 语义。
2. TUI 抽取 spec 体现的边界¶
specs/tui-package.md 把目标 dependency graph 写成:
TUI 可以依赖 terminal / UI infrastructure、Effect 和 generic presentation library,但不应该依赖 packages/opencode、packages/cli 或 @opencode-ai/core 的 backend implementation。
这条约束让“缺一个 UI 需要的字段”变成 API 设计问题,而不是通过 private import 绕过去。
3. UI 状态从哪里来¶
flowchart LR
A[Server HttpApi] --> B[Generated client / sdk]
B --> C[global sync / server connection]
C --> D[project / session stores]
D --> E[home route]
D --> F[session route]
F --> G[timeline / message / tool renderer]
A --> H[SSE / Sync events]
H --> C
App / TUI 首先建立 server connection,再以 project、session、message、permission、question 等 domain state 驱动页面。组件不应该自己重新推断 provider stream,也不应该从日志解析 tool 状态。
4. Session 页面是事件投影的消费者¶
Session UI 需要渲染 assistant text 增量、reasoning、tool 状态、permission / question、file tabs、diff、snapshot、revert、subagent 进度、usage、model、title 和 compaction。
这些都来自 API wire shapes 和 Event V2。UI 的复杂度高,不代表它应该拥有执行语义;它是一个对 durable state 和 event stream 做 projection 的客户端。
5. Desktop 与 ACP 的位置¶
Desktop 是 Electron 宿主,负责窗口、安装包、平台资源,以及启动或连接 server;领域状态仍由 server / SDK 提供。它不是第二个 OpenCode backend。
packages/opencode/src/acp 则把 OpenCode agent 暴露为 ACP agent:接收外部 prompt,映射 directory / session / profile,转发事件、permission、tool、usage,再把内部错误翻译成 ACP 错误。
6. UI 迁移期的阅读方法¶
- 这是纯 presentation 逻辑,还是读取 backend state?
- 如果读取 state,它来自 SDK 还是 private import?
- 事件是否可以通过 Event V2 / Sync 重建?
- 未知 tool / 新 wire field 是否安全 fallback?
- 这是 host concern(启动、认证、进程信号)还是 TUI concern(主题、布局、键位)?
本章小结¶
OpenCode 的多端策略是“共享领域 API,不共享后端私有实现”。TUI / App / Desktop / ACP 都是不同宿主,但它们通过 Client、SDK、Event 和 Schema 共享 Session 语义。