Skip to content

feat(backend): tmux 不可用时明确报错引导,不再静默退回 PTY(PTY 退役第一步)#289

Open
deepcoldy wants to merge 2 commits into
masterfrom
wt/claude-pty-botmux-pty
Open

feat(backend): tmux 不可用时明确报错引导,不再静默退回 PTY(PTY 退役第一步)#289
deepcoldy wants to merge 2 commits into
masterfrom
wt/claude-pty-botmux-pty

Conversation

@deepcoldy

@deepcoldy deepcoldy commented Jun 23, 2026

Copy link
Copy Markdown
Owner

这个 PR 解决什么问题

botmux 每个会话需要一个「终端后端」来跑 CLI,优先用 tmux。以前一旦检测到 tmux 不可用(没装、装坏了、权限不对等),会悄悄改用 PTY 这个简易后端继续跑——用户完全不知道自己被降级了,然后就会一个个踩到 PTY 的固有毛病,最典型的是:PTY 起的会话在 daemon 重启后活不下来,得重新开一个,容易丢上下文。

申晗定了「让 tmux 当唯一默认后端、逐步淘汰 PTY」。本 PR 是第一步,目标很简单:tmux 不行就当场说清楚、引导你装好,而不是偷偷换成 PTY 跑。 这一步先不删 PTY 的代码,只是不再自动用它。

改了什么

  • 默认后端固定为 tmux:不再因为 tmux 探测失败就自动改成 PTY。(config.ts
  • 起会话时,后端不可用就明确拦下:tmux/herdr/zellij 这些后端如果用不了、且当前也没有正在运行的同名会话,就在飞书话题里发一张提示卡(写明原因、安装命令、以及应急开关怎么用),并且不启动这个会话——而不是像以前那样悄悄用 PTY 顶上。已经在运行的 tmux 会话照常重连,不受影响(沿用之前的修复:临时探测失败别误杀已有会话)。(worker.ts
  • 安装阶段的提示改成实话:以前 tmux 装不上会提示「已退回 PTY,常规对话不受影响」——这话现在不成立了。改成明确报错 + 安装命令。(setup/index.ts

保留的「应急开关」

如果你确实在一个没法用 tmux 的环境(比如原生 Windows、极简容器),可以主动设环境变量 BACKEND_TYPE=pty,或给某个机器人单独配 backendType: pty,就还能用 PTY 兜底。提示卡里会写清楚:PTY 会话在 daemon 重启后活不下来,仅供应急。

也就是说——默认强制 tmux、用不了就明确报错;PTY 从「自动兜底」变成「需要你手动打开的应急通道」。

这次先不做的

不删 PTY 的代码。原因有两点:一是删了收益有限(PTY 和 tmux 等后端共用同一套终端转发逻辑,删 PTY 省不掉多少);二是有两件事得先解决——所有会话现在共用一个 tmux 服务,是全机的单点故障,强制全员上 tmux 会放大这个风险,应该先把每个机器人拆成独立 tmux 通道;另外原生 Windows 没有 tmux,要不要彻底放弃得先拍板。

测试

  • 新增针对「该用哪个后端 / 该不该拦」这套判断的单元测试。
  • pnpm build 通过;pnpm test 全绿(376 个测试文件 / 6367 个用例)。

怎么验证

开发机上 tmux 是好的,所以合上来现网行为不变(新会话照常用 tmux、老会话照常重连)。那张拦截提示卡只会在「tmux 真的坏了或没装」的机器上出现,本机看不到效果,需要在没有 tmux 的环境、或人为把 tmux 弄坏来复现。

默认后端恒为 tmux;请求的持久后端(tmux/herdr/zellij)不可用且无存活会话时,
不再静默 spawn 裸 PTY(这是「悄悄跑在 PTY 上、随后撞一堆 PTY 问题」一类 bug 的根源),
改为向话题发一张可操作卡片(原因+安装命令+逃生阀说明)并拒绝启动会话。
PTY 仅保留为显式逃生阀:显式设 BACKEND_TYPE=pty 或 per-bot backendType:pty 才会用。
已存在的 tmux 会话仍照常重连(保留 PR#249 的瞬时探针保护,不误杀)。

- config.ts: detectDefaultBackend() 恒返回 tmux
- worker.ts: 三处 silent pty fallback 合并为硬 gate(decideBackendGate + user_notify + throw)
- setup/index.ts: tmux 装不上从「退回 PTY/不受影响」改为报错+安装指引
- session-backend-selector.ts: 抽纯函数 decideBackendGate / backendGateUserMessage
- 新增 test/backend-gate.test.ts;更新 worker-pipe-initial-screen-order 源码模式断言
@deepcoldy deepcoldy changed the title feat(backend): PTY 退役第一步 —— tmux 不可用改硬 gate 而非静默回退 PTY feat(backend): tmux 不可用时明确报错引导,不再静默退回 PTY(PTY 退役第一步) Jun 23, 2026
Codex review 抓到的 P1:默认后端翻成恒 tmux 后,未持久化 backendType 的旧会话
(在无 tmux 机器上隐式跑 PTY 的) 在 daemon 重启时会被 getSessionPersistentBackendType
按当前默认值推断成 tmux,restore 探到 bmx-<sid> pane 不存在便当僵尸关掉,而不是像
PTY 那样保留 active 记录等下一条消息 lazy resume。

- types.ts: Session 新增 backendType,spawn 时落盘
- worker-pool.ts: fork 时把 initMsg.backendType 落到 session(对齐 cliId 落盘)
- persistent-backend.ts: getSessionPersistentBackendType 优先读 initConfig/session.backendType,
  再读显式 per-bot 配置;三者皆无(=旧会话且 bot 未钉后端)返回 undefined,
  不再回落到现默认值 tmux,从而保守保留旧会话走 lazy resume

附带处理 Codex 的两个 minor:
- worker.ts: zellij 与 tmux 一样先查 hasSession 再探针(保留 PR#249 重连语义),
  herdr 的 isAvailable 是无副作用 --version 无需豁免
- session-backend-selector.ts / ensure-zellij.ts: 订正过时的「fall back to PTY」注释
- 新增 test/persistent-backend-type.test.ts;restore-zombie-close 夹具补 backendType 戳记
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.

1 participant