01c02c6f8f
Fix #67639 根因分析: 子进程继承 fd 0 (stdin) 后设置 O_NONBLOCK 标志时,该标志作用于共享的 open file description 而非单个文件描述符。这导致 gateway 的下一次 read() 返回 EAGAIN,CPython 的缓冲层将其转换为 b'',表现为 EOF,gateway 因此 意外退出。这不是真正的 TUI 关闭管道,而是子进程修改了共享文件状态。 修复涉及三个 Gap: Gap 1 — check_subprocess_stdin.py 扫描范围不足: - 原正则仅匹配 subprocess.run/Popen,扩展到 call/check_output/check_call/ os.system/asyncio.create_subprocess_exec/shell - 新增扫描 ~/.hermes/plugins/ 和 ./.hermes/plugins/ 用户插件目录 (hermes_cli/plugins.py:10-12 定义的插件加载路径) Gap 2 — Gateway 无自愈能力: - entry.py 和 slash_worker.py 的 stdin 循环改为 while True + readline() 模式 - 当 readline() 返回空字符串时,检查 O_NONBLOCK 标志判断是否为虚假 EOF - 虚假 EOF → 恢复 blocking 模式并继续; 真实 EOF → 正常退出 - 添加恢复频率限制 (10次/分钟),防止无限循环 - 添加 _diagnose_stdin_state() 诊断函数,记录 O_NONBLOCK/SO_RCVTIMEO 状态 Gap 3 — 日志消息误导: - 原 "stdin EOF (TUI closed the command pipe)" 改为 "stdin EOF (peer closed)" 或 "stdin spurious EOF (subprocess O_NONBLOCK flip)",附带诊断信息 附带修复: compute_host.py 的 subprocess.check_output 缺少 stdin= 参数