2026/8/31 22:54:04

193、【Agent】【OpenCode】TuiThreadCommand handler:transport 双形态与 TUI 启动

193、【Agent】【OpenCode】TuiThreadCommand handler:transport 双形态与 TUI 启动 【声明】本博客所有内容均为个人业余时间创作所述技术案例均来自公开开源项目如GithubApache基金会不涉及任何企业机密或未公开技术如有侵权请联系删除标题193、【Agent】【OpenCode】TuiThreadCommand handlertransport 双形态与 TUI 启动背景上篇 blog【Agent】【OpenCode】TuiThreadCommand handler从参数到 Worker 就绪拆了thread.tshandler 的前五关一进来先做 Win32 防御win32InstallCtrlCGuardwin32DisableProcessedInput关掉ENABLE_PROCESSED_INPUT防止 CtrlC 杀进程组接着校验--fork必须有--continue或--session来源失败走process.exitCode 1而不是抛异常再解析工作目录——用process.env.PWD优先、cwd兜底解析相对--project路径chdir后取真实cwd统一 thread 与 worker 的 directory key然后target()三级回退OPENCODE_WORKER_PATH→worker.js→worker.ts拉起 Worker最后挂上Rpc.client和三个监听uncaughtException/unhandledRejection/SIGUSR2热重载并备好一个用stopped标志保证只执行一次的幂等stop。至此从参数到 Worker 就绪本篇继续拆后半段stdin 管道、transport 双形态、升级检测与 TUI 启动收尾OpenCodeWorker 已经就绪接下来 handler 要做三件事怎么把 stdin/配置喂进来、用什么方式把 TUI 连上 worker、以及怎么优雅启动和收尾。第六关stdin 管道与配置读取非 TTY 场景比如echo 问题 | opencode下先把 stdin 全量读出来再和--prompt参数拼接成完整 prompt纯 TTY 场景只取参数值。这个函数让 opencode既能交互式运行也能管道式喂单次任务。随后用Instance.provide在指定目录的实例上下文里读取配置thread.ts:170-174——注意directory: cwd配置读取同样绑定到前面统一出来的那个 directory key保证主线程与 worker 用的是同一份实例配置。第七关transport 双形态本篇核心接下来是整套代码里最精巧的设计。先判定外部模式还是内部模式判定规则命令行显式给了--port/--hostname/--mdns或网络选项不是默认值时走外部模式——让 worker 真起一个 HTTP server通过 RPC 拿到server返回的 URL 直连否则走内部模式——不监听任何端口url用一个伪地址http://opencode.internalfetch 和 events 全部由 RPC 代理到 worker。内部模式的fetch长这样这是把 TUI 里所有 HTTP 请求搬运到 worker先把请求序列化成{url, method, headers, body}通过 RPC 发给 worker 去真正执行再把结果包成Response返回。对调用方而言它就是一个标准 fetch完全无感知。对应的events则是 EventSource 接口的适配on(handler)订阅 RPC 的event频道接收 worker 推来的实时事件setWorkspace用 RPC 转发。这样实时事件流在内部模式下其实是跑在同一个进程的 worker 里零端口开销。⏰第八关延迟升级检测启动后延迟 1 秒悄悄查一次版本更新unref()保证这个定时器不会阻塞进程退出失败直接.catch(() {})吞掉绝不打扰启动流程。第九关启动 TUI 与双层收尾tui()是主循环直到 TUI 退出才 resolve。收尾是双层 finally内层先停 Worker走 stop 的软关闭→超时→强杀外层再撤销 Win32 守卫unguard 还原控制台模式。无论 TUI 是正常退出还是抛异常这两步都保证执行最后process.exit(0)确保进程状态干净。整条链路总结维度结果用途stdin 管道非 TTY 读全量 stdin 再拼接 prompt支持交互式 管道式两种用法transport 双形态external 起 server / internal 纯 RPC外部暴露端口 / 内部零端口伪 fetch请求序列化走 RPC 到 worker对调用方无感知的标准 fetch事件源适配RPCevent频道转发实时事件流跑在 worker 里延迟升级检测1s 后 checkUpgrade unref不阻塞退出、失败静默双层 finallystop unguard还原 Worker 与控制台现场一句话记忆后半段 handler 的精华是transport 双形态外部模式开端口直连内部模式用 RPC 把 worker伪装成 fetch 和事件流零端口跑通整个 TUI最后靠双层 finally 保证 Worker 与控制台现场必然还原。OK本篇先到这里如有疑问欢迎评论区留言讨论祝各位功力大涨技术更上一层楼更多内容见下篇 blog【Agent】【OpenCode】工作目录解析PWD、chdir 与 directory key