# 踩坑实录(全部实战验证过的解法) ## 1. xclip 会挂起整个 ssh 会话 `xclip -selection clipboard` 设置剪贴板后会**驻留为剪贴板所有者**,占住 ssh 的 stdout 管道,远程命令永不返回,还会导致后续 cat 截图文件拿到 0 字节。 **解法**:setsid 分离 + 三重丢弃: ```bash setsid xclip -selection clipboard -i /tmp/clip.txt >/dev/null 2>&1 < /dev/null & ``` ## 2. pkill 的模式匹配会杀掉脚本自己 远端脚本里写 `pkill -f "xclip -selection"`,如果脚本自己的命令行里也含这个字样(bash -c 整段就是命令行),**脚本会杀掉自己**,exit 255,后面的命令全不执行。括号技巧 `pkill -f "[x]clip"` 只对 grep/pkill 自身有效,**保护不了内嵌在脚本命令行里的字符串**。 **解法**:需要结束时用 `pkill -x xclip`(精确进程名);脚本里尽量不写 pkill。 ## 3. 微信窗口被藏进托盘 点击搜索下拉、Esc、某些误操作会把窗口最小化到托盘,`wmctrl -l` 里看不到 Weixin,但进程活着。此时截屏全是桌面壁纸,Agent 变瞎,还会把壁纸当界面乱点。 **解法**:每轮轮询前 ensure_window():`wmctrl -l` 无 Weixin 就 `xdotool search --class wechat` 拿窗口 id,`wmctrl -i -a ` 拉回,再重新最大化。agent.py 已内置。 ## 4. "Hide pinned chats" 折叠开关 微信聊天列表底部有折叠置顶的开关。**点击列表底部区域(y>826)极易误触它**,把置顶会话全部折叠——File Transfer 这类内置会话通常在置顶区,折叠后就"消失"了。折叠后列表顶部会出现 "N pinned chats" 字样。 **解法**:① 图标定位的 y 搜索上限设 826,永不进入开关区;② 发送前检测折叠条(vision 问 (60,240)-(300,285) 区域有无 pinned chats 字样),有就点 (160,260) 展开;③ 点图标用图标列中心 x=91,不用行中心。 ## 5. File Transfer(文件传输助手)搜不到 英文 UI 下文件传输助手显示为 "File Transfer",且**搜索框的本地索引不收录它**——搜什么只会出网络搜索建议,点建议还会把窗口搞进托盘。 **解法**:用像素特征在列表里直接找:File Transfer 图标是绿圈+大白箭头,36px 高的窗口内 绿>250 且 白>250 双特征,取最底部匹配。绿 (1,194,96),判定 `r<80 and g>160 and 6020 视为空`。agent.py 的 chat_header_name 已实现。 ## 8. UI 是英文的 官方 Linux 微信跟随系统 locale,Ubuntu Server 默认英文 → 界面全是 "Search"/"File Transfer"/"Send"。给视觉模型的提示词要用英文界面词;联系人名以**界面显示名**为准(用户嘴里的"文件传输助手"=界面上的"File Transfer")。想要中文界面,在 xstartup 里 `export LANG=zh_CN.UTF-8` 并装 language-pack-zh-hans。 ## 9. 发消息点进群聊(最严重事故) 坐标偏移 + 无核验 = 私聊消息发进 227 人群。除了发送前标题核验,还有两条纪律: - 新坐标/新流程**永远先拿 File Transfer 做小白鼠**,不拿真人会话试; - 视觉定位返回的坐标,点击后必须再截屏核验"现在开的是不是目标会话",一步都不省。 ## 10. 2G 内存配置基准 xfce(300M) + 微信(500M-1G) + Agent(PIL+requests 约 30M):available 常态 500M 左右。free -h 的 available < 200M 时先查 evolution 系列有没有复活,再考虑升配。evolution-alarm-notify 会在 xfce 会话每次重启时试图复活,Hidden=true 覆盖文件必须常驻。 ## 11. systemd 服务里拉起的微信秒退(HOME 缺失) systemd 服务环境默认**没有 HOME**。从 agent 进程里 Popen 启动微信,微信因写不了 `~/.xwechat` 立即退出,表现为"拉起后 ps 里没有进程"。解法:service 单元加 `Environment=HOME=/root`,且 agent.py 里 ENV 显式补 HOME。 ## 12. wmctrl -lG 列序:`[3]` 是 y 不是宽度 `wmctrl -lG` 输出为 `id desktop x y W H name`,取宽度必须用 `split()[4]`。取错列会把 y=27(最大化窗口)当成"27px 的小窗口",整个状态机判断全歪。 ## 13. 窗口未映射 ≠ 进程死亡(过渡态绝不能杀) 刚登录成功/启动中的微信,主窗口有几秒未映射期(wmctrl -lG 里没有 Weixin,但 pgrep 有进程)。如果把这当"进程死了"去 pkill+重启,**会杀掉刚登录的会话,用户被迫重新手机确认**。判据:窗口缺失时先 `pgrep -x wechat`,进程活着就只等待+激活,永远不要在进程存活时走硬重启。 ## 14. 登录二维码窗的绿字 vs Log In 按钮都是微信绿 二维码登录窗上 "Scan to log in" 是绿色文字,和实心 Log In 按钮同色系。按"绿像素总数"判断会误触发点击。可靠判据:**单行连续绿像素数**——按钮 ~170x33 实心块,中心行采样约 75+;文字行零散笔画 ≤30。阈值取 50。 ## 15. 任何自愈动作前先问:会不会毁掉登录态/二维码 微信进程一旦重启:登录退化为二维码,用户必须重新扫码+手机确认。所以自愈逻辑的每一版都要过一遍"最坏情况审查":误重启的代价是什么?亮度阈值、窗口宽判据、进程存活判断,宁可保守(等待)也不激进(重启)。重启冷却 90 秒是底线,不是保险。 ## 16. 视觉模型会照抄提示词里的占位符 glm-4v-flash 对"只输出JSON: {chat_name:'名字', text:'...'}"这类带占位示例的提示词,可能**原样返回占位符**而不是读图(尤其图里没有聊天窗时)。对策:示例值用明显的假内容,代码侧校验(文本长度≥2 且不等于 "..."),不合规按读取失败处理。 ## 17. 多账号陷阱:扫的码不一定是目标账号 桌面版微信记住了账号A,但登录页可 Switch Account;用户重新扫码时可能扫成**另一个账号B**。后果:聊天列表全变、白名单联系人"消失"(搜索只剩 Internet search results)。agent 表面正常,实际监护着错误的身份。 **对策**:①登录后第一件事,核对左上角头像/特征会话是否与白名单匹配;②白名单联系人在当前账号不存在时,搜索只剩网络建议——这是换错号的强信号;③部署时明确告知用户"扫码前确认手机当前登录的是哪个号"。