192、【Agent】【OpenCode】TuiThreadCommand handler:从参数到 Worker 就绪
【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
标题
192、【Agent】【OpenCode】TuiThreadCommand handler:从参数到 Worker 就绪
背景
上篇 blog
【Agent】【OpenCode】TuiThreadCmd(类型推导收尾)
分析了 TuiThreadCmd 命令背后 yargs 的类型推导:infer D是"必要的兜底",当开发者省略type只写default时,类型也能从默认值推断出来,而一旦type与default同时出现,type作为"显式契约"拥有最终解释权;别名Alias<O>的值类型从同一个配置O推导,保证别名与主参数名的类型永远一致;最后还比较了.option()的两个重载——精确匹配在前、宽泛匹配在后,顺序颠倒就会导致精确重载永远无法触发。上篇停在"命令是怎么声明的",本篇顺着handler往下走,看看命令真正启动 TUI 前,代码先做了哪些准备工作
OpenCode
thread.ts:101的handler是"命令行参数 → TUI 界面"的最后一公里。有意思的是,它的第一段不是解析参数、也不是起 Worker,而是两行 Windows 防御代码:
在 Windows 上,ENABLE_PROCESSED_INPUT置位时 Ctrl+C 会变成CTRL_C_EVENT信号,直接杀掉整个进程组,所以 handler 一进来就把它关掉并装上"**持续压制"**的守卫,退出时再通过unguard还原。这套机制完整原理(FFI 加载 kernel32、三层守卫、unhook 还原)涉及另一处源码,本篇先简单带过,后续文章再详细拆解。
🧩第一关:fork 参数校验
--fork的语义是"在旧会话基础上分叉出新会话",必须有--continue或--session提供来源。校验失败不抛异常,而是UI.error提示 +process.exitCode = 1+ 直接return,把退出码留给 shell 判断,干净利落。
🗂️第二关:工作目录解析
这里有个容易被忽略的细节:root用process.env.PWD优先、process.cwd()兜底。注释说明原因——相对--project路径要从启动时的目录解析,而不是 chdir 之后。解析完成后chdir到项目目录,再取 chdir 后的真实cwd作为后续所有操作的 directory key,保证 thread 和 worker 看到的是同一个目录。
⚙️第三关:Worker 启动与三级回退
启动 Worker 前,先要决定 worker 脚本从哪来,target()给了三个来源:
优先级从高到低:构建期注入的环境变量OPENCODE_WORKER_PATH→ 打包产物worker.js→ 开发态源码worker.ts。也就是说,生产环境直接用环境变量指定路径,没指定就用编译产物,只有裸开发环境才回退到源码。
注意env的处理:先把值为undefined的环境变量过滤掉,避免空值污染子进程环境;worker.onerror只负责把加载错误记进日志,不中断主流程。
🔌第四关:RPC 客户端与信号绑定
client通过 RPC 协议与 worker 通信,typeof rpc让client.call有完整类型推断。主线程挂了三个兜底:未捕获异常、未处理 Promise 拒绝都只记日志;SIGUSR2信号触发热重载——发一个reloadRPC 让 worker 自己重载。
🛑第五关:幂等清理 stop
stop用stopped标志保证只执行一次:先撤掉前面挂的三个监听,再发shutdownRPC 让 worker优雅退出——withTimeout(..., 5000)给 5 秒超时,超时或失败只warn不抛错,最后worker.terminate()兜底强杀。整个顺序是"软关闭→超时兜底→强制终止"三级递减。
📌一句话记忆
真正的 TUI 启动之前,handler 要先过五关:防 Ctrl+C、校验 fork、chdir 统一目录、
target()三级回退拉起 Worker、挂上 RPC 与兜底监听,最后备好一个幂等的 stop 兜底清理。到这里"从参数到 Worker 就绪"才算完成。
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!下篇 blog 继续拆 handler 的后半段——transport 双形态(external / internal RPC 代理)、延迟升级检测与 TUI 启动收尾
【Agent】【OpenCode】TuiThreadCommand handler:transport 双形态与 TUI 启动
