18 · 终端、预览与资源遥测
三条高吞吐旁路如何共享 Server 权限边界,却不挤进领域事件主干。
为什么把三者放在一起
终端、预览和资源遥测功能看似无关,却共享一个架构特征:它们都依赖执行机器的平台能力、数据频率高、生命周期独立, 不适合把每个字节/帧/采样写进 orchestration event log。它们通过专用 Manager/stream 提供能力,再只把与 Thread 有关的摘要或引用接入 UI。
Terminal Manager
terminal/Manager.ts
拥有 PTY session:创建、输入、resize、输出订阅、关闭和回收。底层通过 PtyAdapter 抽象运行时差异:
NodePtyAdapter.tsBunPtyAdapter.ts
业务/RPC 不直接 import node-pty 或 Bun API,因此同一 Server composition 可选择平台实现。
Session identity 与授权
Terminal session 必须关联 environment/project/thread 或明确 working directory,并生成不可猜的 session ID。RPC 方法分别授权读/写/创建/关闭, 不能因为用户能读 thread 就默认能向 shell 写命令。
数据面
PTY 输出是 byte stream,可能包含 ANSI、控制序列和非 UTF-8 边界。Server 不应按普通 JSON 文本随意 split;adapter/manager 保持字节/块顺序, 客户端终端 surface 解释。Resize/input 是控制面,output 是流。
重放与背压
客户端断线后需要有限 replay buffer 或新 screen baseline,但不需要永久审计每个字节。缓冲必须有容量边界;慢订阅者超出窗口时重建终端状态, 而不是无限拖住 PTY 读取。输出 fan-out 不能让一个手机慢连接阻塞实际 shell 进程。
清理
Thread 页面关闭不一定等于终端进程应退出;Terminal Manager 的 session policy 决定保留/回收。Server shutdown、显式 close、child exit 都要结算 stream, 并防止 PID/session ID 复用导致旧客户端写入新进程。
Preview:从端口发现到浏览器会话
Server 侧 preview/PortScanner.ts
发现工作区相关监听端口,preview/Manager.ts 管理 preview session 与 URL。普通 Web 客户端可以打开可达 URL,Electron 还能用特权浏览器 surface。
端口扫描必须避免:
- 把所有本机服务无差别暴露给远端客户端;
- 对
0.0.0.0、localhost、IPv6 与容器映射解释不一致; - SSRF 式访问任意内网 URL;
- 端口重用后仍将旧服务认作同一 preview。
Manager 应把“发现的候选端口”“用户打开的 session”“当前可达 URL”分成不同状态。
Electron preview 的额外能力
Desktop preview/Manager.ts 和 BrowserSession.ts 管 webContents/webview,preload 支持元素拾取、标注、快捷键和 agent browser cursor。
PlaywrightInjectedRuntime.ts 为自动化注入受控脚本。安全边界包括:context isolation、禁 Node integration、navigation policy、guest protocol 限制和窄 preload。
当 Agent 需要浏览器工具时,Server MCP preview toolkit 通过明确 handler 与桌面 automation host 协调,不能把任意 Electron handle 暴露给 Provider。
资源遥测:采集、归因、历史
resourceTelemetry/ 追踪 CPU、内存等资源,来源可能是:
- Rust
native/resource-monitor子进程; - Electron main 发布的桌面遥测;
- Server 对 Provider/session/process 的关联。
ResourceAttribution.ts
解决“这个 PID/子进程属于哪个 provider session/thread”。采样本身只是数字,只有可靠归因后 UI 才能回答哪个 Agent 占用资源。
为什么 Rust 辅助进程
跨平台进程树、CPU 与内存采样通常需要系统 API,Node 库可能开销高或信息不一致。小型 Rust binary 可以做高效采集,
Server 用 ResourceMonitorBinary.ts 定位/启动并通过协议读取。Binary 不可用时应降级 telemetry,而不是阻止 Agent 主功能。
历史容量
采样是无限流,ResourceTelemetryHistory 必须用时间/点数窗口保存;客户端进入页面时取 snapshot,再订阅增量。
采样频率要低到不显著影响被测系统,高到能看见异常峰值。原始点不应进入 orchestration event log。
三条旁路仍要共享的规则
| 规则 | Terminal | Preview | Telemetry |
|---|---|---|---|
| Environment scope | working dir/session | port/browser session | process/session mapping |
| 方法级授权 | read/write/create | discover/open/automate | read diagnostics |
| 有界数据 | replay buffer | session/metadata limits | history window |
| 断线恢复 | buffer or baseline | re-query session | snapshot + samples |
| 降级 | PTY adapter unavailable | desktop-only ability hidden | monitor unavailable |
| 清理 | child exit/close | webContents/port stale | sampler process/scope |
可迁移经验
- 高频平台数据使用专用流和有界快照,不要污染领域事件日志。
- 将平台 API 放在 adapter 后,业务只依赖 PTY/preview/telemetry capability。
- 断线恢复协议要针对数据类型设计:终端 buffer、preview re-query、telemetry time window 不应硬套一种 reducer。
- 可选监控/预览失败应局部降级;终端写入和浏览器自动化则需要更高权限范围。
- 资源数字只有在进程/session 归因可靠时才对用户有意义。