---
name: wb-keepalive
description: "WorkBuddy 会话自动保活工具 - 部署并启动悬浮窗保活脚本，每 30 分钟自动向指定会话发送心跳消息防止休眠。关键词：保活、keepalive、自动发消息、悬浮窗保活、心跳消息、防止会话休眠"
version: "1.1.0"
author: "WorkBuddy User"
created: "2026-08-24"
---

# WorkBuddy 会话自动保活 (wb-keepalive)

> **Goal**: 在本容器内部署一个 GUI 悬浮窗保活工具：Firefox(Marionette) 驱动**已登录**的 WorkBuddy 网页，每 30 分钟向用户指定的会话链接真实键入并按 Enter 发送 `keepalive-{时间戳}` 心跳消息。

## When to Use

- 用户说"启动保活 / 帮我保活 / keepalive / 自动发消息防休眠 / 悬浮窗保活"等
- 用户要求检查、重启、排障已有的保活工具

## When NOT to Use

- 用户只是提到"保活"字样但不是要部署/管理此工具（如讨论原理）
- 用户想直接调 API 发消息（已证伪：网关 401，绕不过登录态）

## 工作原理（排障前必读）

- **为什么这么绕**: WorkBuddy 输入框是 Slate 富文本编辑器，只认引擎级真实输入（合成 JS 事件全部无效）；API 直调 401。唯一可行路径 = Marionette 驱动真实键鼠。
- **发送链路**: `navigate(会话链接) → 等 30s → 点击输入框 → Ctrl+A 清空 → send_keys(消息) → 按 Enter 发送`（**不要**点击发送按钮，会导致输入框崩溃）。
- **输入框选择器（关键，勿改）**: `[data-slate-editor='true'][contenteditable='true']`。页面上有一个 `contenteditable='false'` 的假编辑器，选择器少了后半段必命中假的并报 "not reachable by keyboard"。
- **Marionette 是单控制连接**: 同一时刻只能有一个客户端连 2828。AI 验证完必须退出释放，否则用户 GUI 连不上。

## 部署流程（AI 按序执行）

### Step 0: 环境自检（缺啥装啥）

**本 skill 附带两份前置文档**（`docs/` 目录，环境缺失时照做即可）：
- `docs/prereq-1-vnc-desktop-setup.md` — 无图形桌面时，按其 §4+§10 装 XFCE+TigerVNC
- `docs/prereq-2-firefox-i18n-install.md` — 无 Firefox 时，按其 §2 装 Mozilla 官方版（**切勿 apt install firefox，是 snap 壳跑不起来**）

```bash
# 1) 图形桌面(必须有 X, 悬浮窗和 Firefox 都在 X 里跑)
ps aux | grep -E "Xtigervnc|Xvfb|Xorg" | grep -v grep
#   有输出=OK; 无 → 读 docs/prereq-1-vnc-desktop-setup.md 先搭 VNC 桌面, 搭好后回来继续
# 2) Python 依赖
python3 -c "import tkinter" 2>&1 || (apt-get install -y python3-tk)
python3 -c "import marionette_driver" 2>&1 || (pip3 install marionette_driver)
# 3) Firefox
which firefox || ls /opt/firefox/firefox
#   有其一=OK; 都无 → 读 docs/prereq-2-firefox-i18n-install.md 按其 §2 安装官方 tarball 版
#   注意: 装 Firefox 前先确认 VNC 桌面已就绪(前置1), Firefox 需在 X 下运行
```

### Step 1: 部署脚本文件

把本 skill 目录下 `scripts/` 里两个文件复制到 `/workspace/` 并加执行权限（已有旧版则覆盖前先问用户）。

```bash
cp <skill_dir>/scripts/wb-keepalive-gui.py <skill_dir>/scripts/start-keepalive.sh /workspace/
chmod +x /workspace/wb-keepalive-gui.py /workspace/start-keepalive.sh
```

可选：创建桌面图标 `/root/Desktop/workbuddy-keepalive.desktop`，内容 Exec 指向 `/workspace/start-keepalive.sh`。

### Step 2: 启动 Firefox(Marionette)

```bash
(ss -ltn | grep -q ':2828') || (export DISPLAY=:1; nohup firefox --no-sandbox --marionette >/tmp/firefox_marionette.log 2>&1 &)
# 轮询等 2828 就绪, 最多 25s
for i in $(seq 1 25); do ss -ltn | grep -q ':2828' && break; sleep 1; done
```

### Step 3: 【人工步骤，必须停下】引导用户登录

1. 用 Marionette 打开 `https://www.workbuddy.cn`（或让用户自己在该 Firefox 里打开）。
2. **明确告诉用户**: 请在 VNC 桌面的 Firefox 里完成登录，登录好了回复一声。
3. **等待用户确认**，禁止跳过。登录态是 cookie，脚本无法代替。
4. 用户确认后，AI 可导航到会话页并执行 `return location.href` 复核（未跳登录页=OK）。

### Step 4: 获取保活目标会话链接并写入

1. 问用户要"要保活的会话链接"（网页版打开该会话，复制地址栏 URL，形如 `https://www.workbuddy.cn/app/task/<convId>`）。
2. 写入脚本（复用脚本自带记忆机制，勿手改错行）：

```bash
python3 - <<'PY'
import importlib.util
spec = importlib.util.spec_from_file_location("wbk", "/workspace/wb-keepalive-gui.py")
m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
m._persist_default("用户提供的链接")   # ← 替换为真实链接
print("已写入:", m.DEFAULT_TARGET_URL)
PY
```

### Step 5: 启动保活悬浮窗

```bash
DISPLAY=:1 nohup /workspace/start-keepalive.sh >/tmp/wb-keepalive-launch.log 2>&1 &
```

告诉用户：VNC 桌面会出现"WB 保活"悬浮窗 → 点「▶ 开始保活」即启动（再点=停止；输入框改链接立即生效；「设为目标」=关掉重开仍记住）。

### Step 6: 端到端自测（AI 自己验证入库，完成后释放连接）

```python
# /tmp/wb_verify.py — 验证一条消息真实入库
import importlib.util, time
spec = importlib.util.spec_from_file_location("wbk", "/workspace/wb-keepalive-gui.py")
m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
ts = int(time.time()); msg = f"keepalive-test-{ts}"
ok, info = m.send_once(m.DEFAULT_TARGET_URL, msg)   # 需 DEFAULT_TARGET_URL 已写入
print("send_once:", ok, info)
time.sleep(3)
c = m._client
page = c.execute_script("return document.body.innerText;") if c else ""
print("RESULT:", "SUCCESS" if (ok and msg in page) else "FAILED")
```

运行 `DISPLAY=:1 timeout 90 python3 /tmp/wb_verify.py`。
- **SUCCESS** → 部署完成，向用户交付使用说明。
- **FAILED** → 按下方排障表逐项检查后重试，最多 3 次；仍失败如实报告卡在哪一步。

> ⚠️ 若 Step 5 的悬浮窗已在「开始保活」发送中，本步骤会因 Marionette 单连接冲突而连不上——先让用户暂停保活再验证。

## 排障表

| 症状 | 根因 | 处置 |
|---|---|---|
| GUI 窗口出不来 / 一点反应没有 | DISPLAY 未指向 VNC 桌面 | 脚本会自动回退 `:1`；确认 `ps aux \| grep Xtigervnc` 存在；无图形可用 `--no-gui` 终端模式 |
| `not reachable by keyboard` | 选择器命中假编辑器 | 必须用 `[data-slate-editor='true'][contenteditable='true']`（脚本已内置，勿改） |
| `Marionette connect failed / Timed out` | 2828 未监听或被其他客户端占用 | `ss -ltn \| grep 2828` 查监听；`pgrep -f wb-keepalive` 查重复实例，杀掉残留再试 |
| 发送后消息残留输入框 / 不入库 | 页面未就绪或登录失效 | NAV_WAIT 默认 30s；复核 Step 3 登录态 |
| 点发送按钮后输入框崩溃 | 已知问题 | 分享版已改用 Enter 发送，确认没人改回 click 版 |
| 消息间隔不对 | 多实例重复发送 | `pgrep -f wb-keepalive-gui.py` 应只有一个进程 |

## 交给用户的使用说明（部署成功后转述）

- 悬浮窗「▶ 开始保活 / ⏸ 停止保活」一键切换；「立即发送」手动补发一条。
- **改目标会话**：直接在输入框粘贴新链接（立即生效）；点「设为目标」则关掉重开仍记住。
- 消息模板/间隔可用环境变量覆盖：`WB_MSG`（默认 `keepalive-{ts}`）、`WB_INTERVAL`（默认 1800 秒）。
- 依赖：保活期间 Firefox 不能关、登录态不能过期；容器重启后重跑 `/workspace/start-keepalive.sh`。
