摘要:写了个 WorkBuddy 自动签到脚本,手动跑一切正常,注册开机自启后却永远不生效——而且不报错。排查下来是两个因素叠加:内置技能目录被写死,加上一个只在 Agent 环境里存在的环境变量。本文记录完整排查过程,附 6 项第三方技能静态审查清单。
WorkBuddy 每天在「Buddy 加油站」可以领一次积分(第 1~6 天各 100,连续第 7 天 1000)。手动点不难,难在每天记得。断一次,连续天数归零,前面攒的计数白费。
所以我打算把它自动化。目标很简单:电脑开着,分自己到账。
网上流传的早期做法是:读出本机登录态里的 accessToken,直接请求官方接口。
这个做法在 WorkBuddy 桌面端 v5.3.8+ 已经不通——客户端把本地登录态从明文 JSON 改成了系统级加密信封:
auth.accessToken = { suite, keyId, nonce, authTag, ciphertext }旧脚本会崩在读取阶段,典型报错是 slice(None, 6, None)。
更重要的是,哪怕能解,我也不想把账号令牌交给一个第三方脚本。
正确做法是走客户端自带的宿主通道(WBIPC):脚本只提交「请求方法 + 接口路径」,鉴权头由客户端自己注入,脚本进程从头到尾碰不到令牌。
from workbuddy_ipc import connect
with connect(client_id="buddy-checkin", client_kind="skill") as wb:
pipe = wb.get_pipe("wb.request")
resp = pipe.invoke("http.fetch", {
"method": "POST",
"path": "/v2/billing/meter/checkin-activity-status",
}, timeout=30)整个签到流程三步:
POST /v2/billing/meter/checkin-activity-status # 查:今天签了吗
POST /v2/billing/meter/daily-checkin # 领(幂等,code=10001 表示已签)
POST /v2/billing/meter/checkin-activity-status # 复核:真的签上了吗第三步是我最看重的:光信「领取」接口返回成功不够,必须再查一次状态确认。否则很容易出现「日志写着成功、实际没签上」,而且没人知道。
第三方技能是要在你机器上跑的代码。我装完先逐文件读了一遍(SKILL.md + 3 个脚本,约 500 行),按 6 类过:
查什么 | 我这次的结果 | |
|---|---|---|
1 | 网络外联 | 无 HTTP 客户端,只用宿主通道转发到 2 个官方 |
2 | 凭据读取 | 全文无读取 token;只对 |
3 | 代码执行 | 无 |
4 | 破坏性操作 | 只写自己的日志目录 |
5 | 持久化 | 会写注册表 |
6 | 依赖与子进程 | 纯标准库零依赖; |
第 5 类特别值得留意:很多人装技能时不看这个,结果机器上多了一堆开机自启项。
方法建议:搜 accessToken、open(、requests、eval|exec|pickle,看命中什么。
装完我手动跑了一次,输出正常:
{"status": "ok", "action": "skip_already_signed", "streak_days": 5}于是顺手注册了开机自启兜底(防止「当天电脑没开机导致断签」)。问题就出在这里。
我没有直接信它,而是模拟了开机自启的实际运行环境——把那个「只在 Agent 环境里存在」的环境变量清掉,再跑一次路径发现函数:
import os
os.environ.pop('CODEBUDDY_BUILTIN_SKILLS_DIR', None) # 模拟计划任务/开机自启场景
print(_add_module_path()) # → None
print(_ipc_ready()) # → False两个都返回空。 意思是:开机自启会找不到宿主通道模块,然后空转 20 分钟、静默放弃——兜底等于白注册,而且不会有任何报错提示你。
脚本里内置技能目录是写死的:
cands.append(os.path.join(
r"C:\Program Files\WorkBuddy\resources\app.asar.unpacked",
"resources", "plugins", "workbuddy-builtin", "skills", "library"))而实际情况是:
D:\Program Files\wb\WorkBuddy\...(路径里多了一层 wb 目录)CODEBUDDY_BUILTIN_SKILLS_DIR 这个环境变量只在客户端/Agent 环境里有值,开机自启、计划任务、crontab 里都没有两个因素叠加,结果是「在对话里跑得好好的,一到无人值守就静默失效」。
把写死路径换成「多来源发现 + 结果缓存」:
def _builtin_skill_roots():
roots = []
env = os.environ.get("CODEBUDDY_BUILTIN_SKILLS_DIR", "").strip()
if env:
roots.append(env)
tail = "resources/app.asar.unpacked/resources/plugins/workbuddy-builtin/skills"
pats = ["/Applications/WorkBuddy.app/Contents/" + tail]
for drv in ("C:", "D:", "E:", "F:", "G:"):
pats.append(drv + "/Program Files/*/WorkBuddy/" + tail) # ← 通配吃掉多出来的那层目录
pats.append(drv + "/Program Files/WorkBuddy/" + tail)
pats.append(drv + "/Program Files (x86)/*/WorkBuddy/" + tail)
for p in pats:
roots.extend(sorted(glob.glob(p)))
roots.append(os.path.join(os.path.expanduser("~"), ".workbuddy",
"plugins", "workbuddy-builtin", "skills"))
return roots关键是那个 *:它把安装路径里「多出来的一层目录」吃掉了,不用再逐个机器改常量。再加个结果缓存,避免轮询期间反复扫盘。
修完复测:
_add_module_path() = D:/Program Files/wb/WorkBuddy/.../skills/library ← 非空
_ipc_ready() = True
兜底脚本实跑 = 2.3 秒完成,日志落地修完之后我又踩了个坑,值得单独说。
签到状态接口返回了一个叫 total_credits 的字段,值是 500。我当时直接把它当成「积分余额」写进了汇报。
直到我做了一次交叉验证——用另一个接口读真实余额,才发现对不上。真实答案是:
total_credits = 连续签到天数 × 每日额度
= 5 天 × 100
= 500 ← 这是「本次活动累计发放」,不是账户余额教训:字段名只是命名,不是契约。凡是「余额 / 总量 / 余量」这类关键数字,至少要拿第二个来源对一次。我这次的对照方法是把两个接口的结果和客户端设置页的显示值三方一比,差 10 倍以内的量级才算通过。
顺带一个副产品:查余额的接口路径和签到接口不在同一个前缀策略下——签到接口必须带 /v2,而资源查询类接口的网关路由声明的是无前缀路径,加了 /v2 反而返回 404 Route Not Found。同一个服务下混用前缀策略,排查时很容易怀疑到自己代码上。
1. 凡是「只在 Agent 环境里能跑」的脚本,都要单独验证「非交互环境」。
判断标准很粗暴:把所有环境变量清掉,它还跑得起来吗? 跑不起来,就说明它在开机自启 / 计划任务 / CI 里一定会静默失效。这类 bug 最坑的地方是它不报错——你会以为它在工作,实际上它什么都没干。
2. 「返回成功」不等于「事情做成了」。
领取类操作一定要加一次独立复核。接口返回 200、日志写 SUCCESS,都可能和真实状态不一致。多查一次的成本,远低于「以为自己签了、结果断签」的成本。
3. 看一个技能安不安全,看它怎么拿凭据比看它功能强不强重要。
「读明文 token 直调接口」和「走宿主通道让客户端注入鉴权头」,功能一样,风险差一个量级。优先选后者。
# 环境自检(模块发现 / 宿主通道 / 接口连通性)
python scripts/checkin.py --diagnose
# 每日签到(幂等,可安全重复执行)
python scripts/checkin.py
python scripts/checkin.py --check-only # 仅查询,不领取
# 开机兜底
python scripts/checkin_on_start.py
python scripts/register_autostart.py --install # 注册
python scripts/register_autostart.py --status # 查看
python scripts/register_autostart.py --uninstall # 撤销这次踩的三个坑,本质是同一类问题:「看起来在工作」和「真的在工作」之间的差距。
total_credits,但不是余额(缺交叉验证)三个坑的共同解法只有一个:不要相信"没有报错",要去独立验证结果。
最后一句提醒:跑自动签到和接任务前,先看清楚脚本会读什么、写什么、连哪里。 省下的时间,不值得拿账号去换。
本文记录的是本机真实跑过的排查过程,所有命令与代码均来自实际调试。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。